home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / ImageWriterLQ (alt. rdip) / UniversalMessageIntf.c < prev    next >
Encoding:
Text File  |  1995-04-10  |  86.4 KB  |  2,809 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------
  2. FILENAME
  3.     UniversalMessageIntf.c
  4.  
  5. DESCRIPTION
  6.     This file contains the routines which override the universal imaging 
  7.     messages that the ImageWriter LQ utilizes.
  8.         
  9. COPYRIGHT
  10.     Copyright Apple Computer, Inc. 1992-1994
  11.     All rights reserved. 
  12.     
  13. INTERFACE ROUTINES:
  14.     SD_Initialize
  15.     SD_ShutDown
  16.     SD_JobFormatDialog
  17.     SD_JobFormatModeQuery
  18.     SD_OpenConnection
  19.     SD_StartSendPage
  20.     SD_RenderPage
  21.     SD_DefaultPrinter
  22.     SD_SetupImageData
  23.     SD_FetchTaggedData
  24.     SD_RasterPackageBitmap
  25.     SD_RasterLineFeed
  26.  
  27.     12/20/93        dmh    Sync'd with the shipping 1.0b3 GX driver.
  28.      8/28/94        dmh    Sync'd with the shipping 1.0.1 GX driver.
  29.      8/28/94        dmh    Universalized.
  30.  
  31. -------------------------------------------------------------------------------- */
  32.  
  33. // Include the standard Mac header files 
  34. #include "MacIncludes.h"
  35.  
  36. // Include the new QuickDraw GX graphics header files 
  37. #include <graphics routines.h>
  38. #include <graphics libraries.h>
  39. #include <math routines.h>
  40. #include <qd library.h>
  41. #include <font library.h>
  42. #include <layout routines.h>
  43. #include <graphics libraries.h>
  44.  
  45. // Include the required Printing Manager header files 
  46. #include <PrintingManager.h>
  47. #include <PrintingMessages.h>
  48. #include <PrintingDrivers.h>
  49. #include <Collections.h>
  50. #include <Messages.h>
  51. #include <PrintingResTypes.h>
  52. #include <PrintingErrors.h>
  53. #include <PrintingLibraries.h>
  54.  
  55. #include <GXExceptions.h>
  56.  
  57. // Include the internal driver constants and types used by this module 
  58. #include "Resources.h"
  59. #include "UniversalMessageIntf.h"
  60. #include "OldAPIMessageIntf.h"
  61. #include "DialogRoutines.h"
  62.  
  63. /***************************************************************************************
  64. *                                                 CONSTANTS                                                         *
  65. ***************************************************************************************/                        
  66.  
  67. // ImageWriter LQ device commands
  68.  
  69. #define    kEscape                            (char) 27        // <Escape> character
  70. #define    kLineFeed                        (char) 10        // Line feed character
  71. #define    kDevStatusCommand                "\033?"            // <Escape>? - used to query the status of the printer
  72.  
  73. #define    kLowResGraphicsCommand        (char) 'G'        //    72 dpi graphics mode
  74. #define    kHighResGraphicsCommand        (char) 'C'        //    216 dpi graphics mode
  75.  
  76. #define    kLowResMarginsCommand        (char) 'F'        //    72 dpi margins command
  77. #define    kHighResMarginsCommand        (char) 'h'        //    216 dpi margins command
  78.  
  79. #define    kSetColorCommand                (char) 'K'        //    Command to select color
  80.  
  81.  
  82. // Constants used with the ScanLineRecord structure
  83.  
  84. #define    kScanLineHdrSize                15                    //    Size of the constant portion of the scan line structure
  85.  
  86.  
  87. /***************************************************************************************
  88. *                                                 TYPES                                                                 *
  89. ***************************************************************************************/                        
  90.  
  91. // ScanLineRecord -    Structure overlayed within a buffer to fill in the comands and data needed to
  92. //                            package one complete scan line.
  93. typedef struct
  94. {
  95.     char        cMarginsEscape;            // kEscape character
  96.     char        cMarginsCommand;            // Set Margins command character
  97.     char        cIndentDistance[4];        // Number of pixels to indent
  98.  
  99.     char        cColorEscape;                // kEscape character
  100.     char        cSetColorCommand;            // Set color command
  101.     char        cColor;                        // The color to use
  102.  
  103.     char        cEscape;                        // kEscape character
  104.     char        cCommand;                    // Enter graphics mode command
  105.     char        cLineStrLength[4];            // number of dots to print
  106.     char        iTheData[9072];            // Bits for the data, enough for one line's worth
  107. }    ScanLineRecord,
  108.     *ScanLinePtr;
  109.  
  110.  
  111. /***************************************************************************************
  112. *                                         INTERNAL ROUTINES                                                     *
  113. ***************************************************************************************/                        
  114.  
  115. /****************************************************************************************
  116.  
  117.                             Long2Dec
  118.                             
  119.     function:
  120.                 This routine converts a long integer into an ASCII string representing the
  121.                 numeric value.  If the number is less than four digits, then it's padded
  122.                 with leading zeros.
  123.                 
  124.     parameters:                
  125.                 theNumber            number to convert to a string
  126.                 emitStringHere        location in which to store the ASCII string
  127.                 
  128.     returns:
  129.                 none
  130.     
  131. ****************************************************************************************/
  132. void Long2Dec(long theNumber, Ptr emitStringHere)
  133. {    
  134.     char        aString[10];
  135.     short        i;
  136.     short        actualWidth;
  137.     short        theLength;
  138.     
  139.     NumToString(theNumber, aString);
  140.     
  141.     // Get the width of the string, check for being too small
  142.  
  143.     theLength = StrLength(aString);
  144.     actualWidth = theLength;
  145.     if (actualWidth < 4)
  146.         actualWidth = 4;
  147.         
  148.     // output the string, padding with leading zeros
  149.     
  150.     theLength = actualWidth - theLength;
  151.     for (i = 0; i < actualWidth; ++i)
  152.     {
  153.         *emitStringHere++ = (i < theLength) ? '0' : aString[(i + 1) - theLength];
  154.     }
  155. }
  156. /* Long2Dec */
  157.  
  158.  
  159. /****************************************************************************************
  160.  
  161.                             PrinterHasColorRibbon
  162.                             
  163.     function:
  164.                 This routine is a utility function that returns true if the desktop printer
  165.                 configuration file specifies that the printer contains a color ribbon, and
  166.                 false if it has a black and white ribbon.
  167.                 
  168.     parameters:                
  169.                 None
  170.                 
  171.     returns:
  172.                 Boolean        true => printer has color ribbon; false => black and white ribbon
  173.     
  174. ****************************************************************************************/
  175. Boolean PrinterHasColorRibbon(void)
  176. {
  177.     OSErr                        anErr;
  178.     Boolean                    hasColor = true;
  179.     Str32                        deviceName;
  180.     IWLQConfigInfoHdl        configData;
  181.     
  182.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  183.  
  184.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  185.     if ( StrLength(deviceName) > 0 )
  186.     {
  187.         // if we are going to a particular device, assume no color, as that is more common
  188.         hasColor = false;
  189.         
  190.         anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
  191.         if (anErr == noErr)
  192.         {
  193.             hasColor = (*configData)->hasColorRibbon;
  194.             DisposHandle((Handle) configData);
  195.         }
  196.     }
  197.     
  198.     return(hasColor);
  199. }
  200. /* PrinterHasColorRibbon */
  201.  
  202.  
  203. /****************************************************************************************
  204.  
  205.                             PrinterHasTrays
  206.                             
  207.     function:
  208.                 This routine is a utility function that returns the number of sheet feeder trays
  209.                 that are attached to the desktop printer.  If no sheet feeder is attached, then 
  210.                 the function returns zero.
  211.                 
  212.     parameters:                
  213.                 None
  214.                 
  215.     returns:
  216.                 char        number of sheet feeder trays attached to the printer; zero if no sheet feeder
  217.     
  218. ****************************************************************************************/
  219. char PrinterHasTrays(void)
  220. {
  221.     OSErr                        anErr;
  222.     char                        numTrays = 0;    //    Assume no trays available (common case)
  223.     Str32                        deviceName;
  224.     IWLQConfigInfoHdl        configData;
  225.     
  226.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  227.  
  228.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  229.     if ( StrLength(deviceName) > 0 )
  230.     {
  231.         anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
  232.         if (anErr == noErr)
  233.         {
  234.             numTrays = (*configData)->numTrays;
  235.             DisposHandle((Handle) configData);
  236.         }
  237.     }
  238.     
  239.     return(numTrays);
  240. }
  241. /* PrinterHasTrays */
  242.  
  243.  
  244. /****************************************************************************************
  245.  
  246.                             UpdateDTPConfigInfo
  247.                             
  248.     function:
  249.                 This routine is a utility function that queries the printer to determine its
  250.                 configuration (color ribbon, trays, etc.) and updates the config info. in the
  251.                 desktop printer file to reflect this new configuration.
  252.                 
  253.     parameters:                
  254.                 None
  255.                 
  256.     returns:
  257.                 OSErr        error code
  258.     
  259. ****************************************************************************************/
  260. OSErr UpdateDTPConfigInfo(void)
  261. {
  262.     OSErr                        anErr;
  263.     IWLQConfigInfoHdl        configData;
  264.     char                        statusString[9];
  265.     long                        statusStrLength;
  266.     Boolean                    wasSheetfeederAttached;
  267.     gxJob                        theJob = GXGetJob();
  268.         
  269.     // Determine if there was a sheetfeeder attached to the printer the last time we updated the config file
  270.     wasSheetfeederAttached = PrinterHasTrays() > 0;
  271.     
  272.     // Make a handle in which to store the config. info.
  273.     
  274.     configData = (IWLQConfigInfoHdl) NewHandleClear( sizeof(IWLQConfigInfo) );
  275.     anErr = MemError();
  276.     require(anErr == noErr, NewHandleClear);
  277.     
  278.     // Now query the printer
  279.     
  280.     statusStrLength = 9;
  281.     
  282.     anErr = Send_GXGetDeviceStatus(kDevStatusCommand, 2, statusString, &statusStrLength, "\p\n");
  283.     require(anErr == noErr, Send_GXGetDeviceStatus);
  284.     
  285.     // Scan the status string returned looking for the needed info.
  286.     
  287.     if ( (statusString[0] == 'L') && (statusString[1] == 'Q') )
  288.     {
  289.         Str32        deviceName;
  290.  
  291.         if ( statusString[3] == 'C' )    //    T => Has color ribbon
  292.         {
  293.             (*configData)->hasColorRibbon = true;
  294.         }
  295.         
  296.         if (  (statusString[3] == 'E') || 
  297.                 (statusString[3] == 'F')
  298.             )                                            //    T => Sheet feeder is installed
  299.         {
  300.             (*configData)->numTrays = statusString[4] - 0x30;
  301.         }
  302.         else
  303.         if (    (statusString[4] == 'E') ||
  304.                 (statusString[4] == 'F')
  305.             )                                            //    T => Sheet feeder is installed
  306.         {
  307.             (*configData)->numTrays = statusString[5] - 0x30;
  308.         }
  309.  
  310.         //    Update the config. file with the latest info. (our driver info.)
  311.         
  312.         GXGetPrinterName(GXGetJobOutputPrinter(theJob), deviceName);
  313.         anErr = GXWriteDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle) configData);
  314.         require(anErr == noErr, WriteDTPData);
  315.  
  316.         // If this is the first time we've detected a sheet feeder, then we must set the tray info. (in the config. file)
  317.         // for the sheet feeder trays.  If this isn't the first time we've detected a sheetfeeder, we'll just use
  318.         // the last sheetfeeder tray settings.
  319.         
  320.         if ( (!wasSheetfeederAttached) && ((*configData)->numTrays > 0) )    //    T => No sheetfeeder before; clear the tray info.
  321.         {
  322.             GXSetTrayPaperType(1, NULL);    /* Reset the paper types from the default tray */
  323.         }
  324.         else if ( wasSheetfeederAttached && ((*configData)->numTrays == 0) )    //    T => Sheetfeeder before; clear the tray info.
  325.         {
  326.             GXSetTrayPaperType(1, NULL);    /* Reset the paper types from the first tray, ignore the others */
  327.         }
  328.     }
  329.     // else - not an LQ printer so don't change the config file info.
  330.  
  331.     // Dump the confog. data handle
  332.     DisposHandle((Handle) configData);
  333.  
  334.     return(anErr);
  335.     
  336.     
  337. /******* Clean-up *******/
  338.  
  339. WriteDTPData:
  340. Send_GXGetDeviceStatus:
  341.     DisposHandle((Handle) configData);
  342.     
  343. NewHandleClear:
  344.     return(anErr);
  345. }
  346. /* UpdateDTPConfigInfo */
  347.  
  348.  
  349. /****************************************************************************************
  350.  
  351.                             FixRoundRectangle
  352.                             
  353.     function:
  354.                 This routine is a utility function which rounds the coordinate values within 
  355.                 the rectangle passed in.
  356.                 
  357.     parameters:                
  358.                 r            rectangle whose coordinates are to be rounded
  359.                 
  360.     returns:
  361.                 None
  362.     
  363. ****************************************************************************************/
  364. void FixRoundRectangle(gxRectangle *r)
  365. {
  366.     r->top         = ff(FixRound(r->top));
  367.     r->left         = ff(FixRound(r->left));
  368.     r->bottom     = ff(FixRound(r->bottom));
  369.     r->right     = ff(FixRound(r->right));
  370. }
  371. /* FixRoundRectangle */
  372.  
  373.  
  374. /****************************************************************************************
  375.  
  376.                             JobIsBestQuality
  377.                             
  378.     function:
  379.                 This routine is called to determine if the job the driver is currently
  380.                 processing is to be output in best quality or rough quality. The function
  381.                 returns true if best quality, and false otherwise.
  382.                 
  383.     parameters:    
  384.                 None
  385.                 
  386.     returns:
  387.                 Boolean        true if best quality job; false otherwise
  388.     
  389. ****************************************************************************************/
  390. Boolean JobIsBestQuality(void)
  391. {
  392.     OSErr                    anErr;
  393.     Boolean                isFinal;
  394.     gxQualityInfo        jobQualitySettings;
  395.     long                    itemSize = sizeof(jobQualitySettings);
  396.  
  397.     // Retrieve the quality setting info from the job
  398.     anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
  399.     check(anErr == noErr);
  400.     
  401.     isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
  402.  
  403.     return(isFinal);
  404. }
  405. /* JobIsBestQuality */
  406.  
  407.  
  408. /****************************************************************************************
  409.  
  410.                             MakeNewPrinterViewDevice
  411.                             
  412.     function:
  413.                 This routine is called to add a new view device to the printer object.  The
  414.                 viewDevice that's added will have a resolution of 216 dpi, and will have the
  415.                 set of colors specified by the theColors parameter.  The newly created 
  416.                 view device is added to the printer object.
  417.                 
  418.     parameters:                
  419.                 thePrinter        the newly allocated printer object
  420.                 theColors        the colors over which the view device is defined
  421.                 numColrs            the number of colors in the set
  422.                 
  423.     returns:
  424.                 OSErr
  425.                 
  426. ****************************************************************************************/
  427. OSErr MakeNewPrinterViewDevice(    gxPrinter        thePrinter,
  428.                                             gxSetColor        theColors[],
  429.                                             short                numColors)
  430. {
  431.     OSErr             anErr = noErr;
  432.     gxViewDevice     vd;
  433.     gxMapping        vdMapping;
  434.     gxShape            theBitmap;
  435.     gxColorSet        theColorSet;
  436.     
  437.     // Create the new viewDevice using a fake bitmap 
  438.     {
  439.         gxBitmap    aBitmap;
  440.         
  441.         aBitmap.pixelSize    = 1;
  442.         aBitmap.rowBytes    = 0;
  443.         aBitmap.width        = 0;
  444.         aBitmap.height        = 0;
  445.         aBitmap.image        = (char*)gxMissingImagePointer;
  446.         aBitmap.space        = gxNoSpace;
  447.         aBitmap.set            = nil;
  448.         aBitmap.profile    = nil;
  449.         
  450.         theBitmap = GXNewBitmap(&aBitmap, nil);
  451.         require_action( GXGetGraphicsError(nil) == noErr, NewBitmap, anErr = GXGetGraphicsError(nil); );
  452.         
  453.         vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
  454.         require_action( GXGetGraphicsError(nil) == noErr, NewViewDevice, anErr = GXGetGraphicsError(nil); );
  455.  
  456.         // Dispose of the reference to the temporary shape
  457.         GXDisposeShape(theBitmap);
  458.     }
  459.     
  460.     // Now set the view device's color space based on the set of colors passed in 
  461.     {
  462.         theColorSet = GXNewColorSet(gxRGBSpace, numColors, theColors);
  463.         require_action( GXGetGraphicsError(nil) == noErr, NewColorSet, anErr = GXGetGraphicsError(nil); );
  464.  
  465.         SetViewDeviceColorSet(vd, theColorSet);
  466.         require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
  467.     
  468.         // Dispose of the reference to the temporary shape
  469.         GXDisposeColorSet(theColorSet);
  470.     }
  471.     
  472.     // Change the viewDevice mapping to include the scaling factor from 72dpi (screen) to 216 dpi (device). 
  473.     {
  474.         ResetMapping(&vdMapping);
  475.         ScaleMapping(&vdMapping, ff(3), ff(3), ff(0), ff(0));
  476.         
  477.         GXSetViewDeviceMapping(vd, &vdMapping);
  478.     }
  479.     
  480.     // Add the newly created viewDevice to the printer object 
  481.  
  482.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  483.     require_action( GXGetGraphicsError(nil) == noErr, AddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
  484.     
  485.     return(anErr);
  486.     
  487.     
  488. /******* Clean-up *******/
  489.  
  490. SetViewDeviceColorSet:
  491.     GXDisposeColorSet(theColorSet);
  492.  
  493. AddPrinterViewDevice:
  494. NewColorSet:
  495.     GXDisposeViewDevice(vd);
  496.     return(anErr);
  497.  
  498. NewViewDevice:
  499.     GXDisposeShape(theBitmap);
  500.  
  501. NewBitmap:
  502.     return(anErr);
  503. }
  504. /* MakeNewPrinterViewDevice */
  505.  
  506.  
  507. /****************************************************************************************
  508.  
  509.                             WriteDraftChars
  510.                             
  511.     function:
  512.                 This routine is called to output a single character in the native set of the
  513.                 printer.  The draftTable parameter contains long word entries for each possible
  514.                 character that can be printed.  Each long word entry is composed of two word entries,
  515.                 where the first word represents the primary character to output and the second
  516.                 word optionally specifies an overstrike character.  If an overstrike character
  517.                 is specified, then we will overstrike the second character on the first.  The format
  518.                 of each word is the same and is as follows:
  519.                 
  520.                 bit 15         -    0 => don't backspace before writing character
  521.                                     1 => backspace first before printing the character
  522.                 
  523.                 bits 14:12    -    0
  524.  
  525.                 bits 11:8    -    national character set to invoke (e.g. kAmerican)
  526.  
  527.                 bits 7:0        -    the character to send to the printer (must be != 0 to be output)
  528.                 
  529.     parameters:    
  530.                 draftTable        Handle to an array of long word entries that describe how to output
  531.                                     each printable character in draft mode
  532.                 draftChar        Pointer to the ASCII characters that are to be output
  533.                 numChars            Number of characters to be output
  534.                 
  535.     returns:
  536.                 OSErr
  537.     
  538. ****************************************************************************************/
  539. OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
  540. {
  541.     OSErr        anErr = noErr;
  542.     char        outputChars[20];                // a maximum of 20 characters can be generated
  543.     short        charCount;                    
  544.     
  545.     // For each character in the buffer, determine how to map the character to a draft character
  546.     for (; numChars > 0; --numChars, ++draftChar)
  547.     {
  548.         // No characters yet for this output character
  549.         charCount = 0;
  550.             
  551.         // Only consider characters in the printable range
  552.         if (*draftChar >= 0x20)
  553.         {
  554.             unsigned long    draftControl = (*draftTable)[*draftChar-0x20];    // Fetch native mode long word corresponding to this character
  555.             unsigned char    outChar;
  556.             unsigned char    nationalSet;
  557.             short                i;
  558.             
  559.             // For each word which composes the native mode long word 
  560.             for (i = 1; i >= 0; --i)
  561.             {
  562.                 // Should we send a backspace character (to overstrike)?
  563.                 if ( (draftControl & 0x80000000) != 0 )
  564.                     outputChars[charCount++] = 0x08;
  565.                 
  566.                 outChar = (draftControl >> 16) & 0xFF;
  567.                 if (outChar != 0)
  568.                 {
  569.                     // Determine the national character set to select
  570.                     nationalSet = (draftControl >> 24) & 0xF;    
  571.     
  572.                     //    Is this character in the standard, built-in character set?
  573.                     if (nationalSet == kAmerican)
  574.                     {
  575.                         outputChars[charCount++] = outChar;
  576.                     }
  577.                     else    //    T => Must select a foreign language character set 
  578.                     {
  579.                         outputChars[charCount++] = 0x1B;
  580.                         outputChars[charCount++] = 0x44;
  581.                         outputChars[charCount++] = nationalSet;
  582.                         outputChars[charCount++] = 0x00;
  583.                         outputChars[charCount++] = outChar;
  584.                         outputChars[charCount++] = 0x1B;                // We always switch back to the kAmerican character set
  585.                         outputChars[charCount++] = 0x5A;
  586.                         outputChars[charCount++] = 0x07;
  587.                         outputChars[charCount++] = 0x00;
  588.                     }
  589.                 }
  590.                 
  591.                 // Take the next (low) word and process it (if we're not all done)
  592.                 draftControl <<= 16;
  593.             }    
  594.         }
  595.             
  596.         // If we generated any data, send it out now
  597.         if (charCount > 0)
  598.             anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
  599.     }
  600.         
  601.     return(anErr);    
  602.     
  603. /* WriteDraftChars */
  604.  
  605.  
  606. /****************************************************************************************
  607.  
  608.                             GetPointerThisBig
  609.                             
  610.     function:
  611.                 This routine is called to return a pointer (in the heap) to the number of
  612.                 bytes specified by numBytes.  If the pointer is already large enough, then
  613.                 this routine simply returns the existing pointer.  Otherwise, it allocates
  614.                 a new pointer (possibly disposing of the old one) of the specified size.
  615.                 
  616.     parameters:    
  617.                 theBuff            returns a pointer to the allocated buffer 
  618.                 numBytes            required size of the pointer returned (in bytes)
  619.                 
  620.     returns:
  621.                 OSErr
  622.     
  623. ****************************************************************************************/
  624. OSErr GetPointerThisBig(Ptr *theBuff, long numBytes) 
  625. {
  626.     OSErr        anErr = noErr;
  627.     
  628.     if (*theBuff != nil)
  629.     {
  630.         if ( GetPtrSize(*theBuff) < numBytes )    //    T => Won't be big enough; make a new one
  631.         {
  632.             DisposPtr(*theBuff);
  633.             *theBuff = nil;
  634.         }
  635.     }
  636.  
  637.     if (*theBuff == nil)
  638.     {
  639.         *theBuff = NewPtrClear(numBytes);
  640.         anErr = MemError();
  641.     }
  642.     
  643.     return(anErr);
  644. }
  645. /* GetPointerThisBig */
  646.  
  647.  
  648. /****************************************************************************************
  649.  
  650.                             GetTextAndPosition
  651.                             
  652.     function:
  653.                 This routine is called to return information about the layout shape
  654.                 referenced by the theShape parameter.  It returns a pointer to the
  655.                 text data in theChars, the number of characters in the data in numChars, and
  656.                 a pointer to the positions of the characters in textPositions.  The caller
  657.                 is responsible for disposing of the pointers returned in theChars and
  658.                 textPositions.
  659.                 
  660.     parameters:    
  661.                 theShape            reference to the shape to be examined
  662.                 theChars            returns a pointer to the text characters
  663.                 numChars            returns the number of characters in the text shape
  664.                 textPosition    returns the position of the layout shape
  665.                 
  666.     returns:
  667.                 OSErr
  668.     
  669. ****************************************************************************************/
  670. OSErr GetTextAndPosition(    gxShape            theShape, 
  671.                                     Ptr            *theChars, 
  672.                                     long            *numChars, 
  673.                                     gxPoint            *textPosition)
  674. {
  675.     OSErr        anErr = noErr;
  676.     long        textStrLength;
  677.     
  678.     // Determine the size of the text data and the position of the text
  679.     textStrLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
  680.  
  681.     // Make sure we have a buffer pointer large enough to hold all of the data
  682.     
  683.     anErr = GetPointerThisBig(theChars, textStrLength);
  684.     require(anErr == noErr, CantAllocTextBuff);
  685.     
  686.     // Now we retrieve the text
  687.     GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
  688.     
  689.     // Remember the number of characters in the shape
  690.     *numChars = textStrLength;
  691.     
  692.  
  693. /******* Clean-up *******/
  694.  
  695. CantAllocTextBuff:
  696.     return(anErr);
  697. }
  698. /* GetTextAndPosition */
  699.  
  700.  
  701. /****************************************************************************************
  702.  
  703.                             PrintPageInDraftMode
  704.                             
  705.     function:
  706.                 This routine is called to print a page using the native character set in the
  707.                 printer.  The page to print is referenced by the thePage parameter.  The routine
  708.                 walks through the picture looking for layout shapes.  Each of these
  709.                 shapes is imaged using the native character set; all other shapes are ignored.
  710.                 This routine assumes the shapes within the picture are y-sorted.
  711.                 
  712.     parameters:    
  713.                 thePage        Reference to the page shape that's to be printed
  714.                 imageData    pointer to the raster image data
  715.                 
  716.     returns:
  717.                 OSErr
  718.     
  719. ****************************************************************************************/
  720. OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
  721. {
  722.     OSErr                    anErr = noErr;
  723.     long                    i;
  724.     long                    numItems;
  725.     Fixed                    currYPos = ff(0);
  726.     Ptr                    theChars = nil;
  727.     long                    numChars = 0;
  728.     gxPoint                textPosition;
  729.     Fixed                    oldTextSize = ff(0);
  730.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  731.     
  732.     // Since the page picture we need to process is a picture shape that's embedded in
  733.     // thePage (a shape containing one item => a picture), we need to extract the real
  734.     // page picture from thePage.
  735.     
  736.     thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
  737.     numItems = GXGetPicture(thePage, nil, nil, nil, nil);
  738.     
  739.     // For each shape within the picture, check its type and process it accordingly
  740.     
  741.     for (i = 1; i <= numItems; ++i)
  742.     {
  743.         gxShape                theShape;
  744.         short                    theType;
  745.         
  746.         theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
  747.         theType = GXGetShapeType(theShape);
  748.         
  749.         if (theType == gxLayoutType)    //    T => We have a layout shape
  750.         {
  751.             fixed        textSize;
  752.             char        buff[12];
  753.             char        theFace;
  754.             short        cmndBuffSz;
  755.             
  756.             // First determine the style in which we're printing
  757.             
  758.             theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
  759.             
  760.             buff[0] = kEscape;
  761.             if ( (theFace & bold) != 0 )    //    T => Turn bold facing on
  762.                 buff[1] = '!';
  763.             else                                    //    T => Turn it off
  764.                 buff[1] = '"';
  765.             
  766.             buff[2] = kEscape;
  767.             if ( (theFace & underline) != 0 )    //    T => Turn underline facing on
  768.                 buff[3] = 'X';
  769.             else                                            //    T => Turn it off
  770.                 buff[3] = 'Y';
  771.                 
  772.             cmndBuffSz = 4;
  773.             
  774.             // Next determine if we need to change the size of the font being used
  775.             
  776.             textSize = GXGetShapeTextSize(theShape);
  777.             if (textSize != oldTextSize)    //    T => Must issue LQ command to change font size
  778.             {
  779.                 buff[4] = kEscape;                //    The first escape command selects black color
  780.                 buff[5] = kSetColorCommand;
  781.                 buff[6] = '0';
  782.                 
  783.                 buff[7] = kEscape;                //    The second escape command selects a draft font
  784.                 buff[8] = 'a';
  785.                 buff[9] = '1';
  786.                 
  787.                 buff[10] = kEscape;                //    The third escape command selects the character pitch
  788.                 
  789.                 if ( textSize <= ff(10) )    //    T => Select 10 cpi
  790.                 {
  791.                     buff[11] = 'N';
  792.                 }
  793.                 else    //    T => All other sizes get mapped to 12 cpi
  794.                 {
  795.                     buff[11] = 'E';
  796.                 }
  797.                 
  798.                 // Remember the last text size
  799.                 oldTextSize = textSize;    
  800.                 
  801.                 // Adjust the size of the data to be sent to the printer
  802.                 cmndBuffSz += 8;
  803.             }
  804.             // else - no change in font size
  805.             
  806.             // Send the commands to the printer
  807.             anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
  808.             require(anErr == noErr, CantSendFontCmnd);
  809.  
  810.             // Get the ASCII text and the starting position of the data
  811.             anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
  812.             require(anErr == noErr, CantGetTextAndPos);
  813.             
  814.             if ( (currYPos != ff(0)) && (currYPos != textPosition.y) )    //    T => Moving to a lower line, finish the last ;line with a CR
  815.             {
  816.                 char        c = 0x0D;
  817.                 
  818.                 anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  819.                 require(anErr == noErr, CantSendCRCmnd);
  820.             }
  821.             
  822.             // Position the print head to the proper location on the page
  823.             {
  824.                 gxMapping            theMapping;
  825.                 short                    lineFeedSize;
  826.                 Str255                positionCmndsBuff;
  827.                 unsigned long        bytesInBuff = 0;
  828.                 char                    *p;
  829.  
  830.                 GXGetShapeMapping(theShape, &theMapping);
  831.                 MapPoints(&theMapping, (long) 1, &textPosition);    //    Just map the first point
  832.                 
  833.                 // Now position the print head vertically
  834.  
  835.                 lineFeedSize = (textPosition.y - currYPos) >> 16;
  836.                 anErr = Send_GXRasterLineFeed(&lineFeedSize, positionCmndsBuff, &bytesInBuff, imageData);
  837.                 require(anErr == noErr, CantEmitLineFeeds);
  838.                 
  839.                 // Update the current Y position pointer on the page
  840.                 currYPos = textPosition.y;
  841.  
  842.                 // Now position the print head horizontally on the page
  843.  
  844.                 p = &positionCmndsBuff[bytesInBuff];        
  845.                 *p++ = kEscape;
  846.                 *p++ = kLowResMarginsCommand;
  847.                 Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p);    // Convert left margin into ASCII and place it at the start of the scan line
  848.                 
  849.                 // Update the number of bytes in the buffer
  850.                 bytesInBuff += 6;
  851.  
  852.                 // Send the positioning info to the printer
  853.                 anErr = Send_GXBufferData(positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
  854.                 require(anErr == noErr, CantSendPositionCmnds);
  855.             }
  856.             
  857.             // Now we send the text data to the printer
  858.             anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, theChars, numChars);
  859.             require(anErr == noErr, CantWriteChars);
  860.         }
  861.     }    // for
  862.  
  863.     // Send one last CR to wrap the last line (if there was one)
  864.     {
  865.         char        c = 0x0D;
  866.         
  867.         anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  868.     }
  869.  
  870.  
  871. /******* Clean-up *******/
  872.  
  873. CantWriteChars:
  874. CantSendPositionCmnds:
  875. CantEmitLineFeeds:
  876. CantSendCRCmnd:
  877. CantGetTextAndPos:
  878. CantSendFontCmnd:
  879.     if (theChars != nil)
  880.         DisposPtr(theChars);
  881.                 
  882.     return(anErr);
  883. }
  884. /* PrintPageInDraftMode */
  885.  
  886.  
  887. /***************************************************************************************
  888. *                                         INTERFACE ROUTINES                                                     *
  889. ***************************************************************************************/                        
  890.  
  891. /****************************************************************************************
  892.  
  893.                             SD_Initialize
  894.                             
  895.     function:
  896.                 This routine is called when a new job is created to perform some job-oriented
  897.                 task, such as conducting dialogs, spooling, and imaging.  It allocates the
  898.                 driver's globals handle and initializes it.
  899.                 
  900.     parameters:    
  901.                 None
  902.                 
  903.     returns:
  904.                 OSErr
  905.     
  906. ****************************************************************************************/
  907. OSErr SD_Initialize(void)
  908. {
  909.     OSErr                 anErr;
  910.     SpecGlobalsHdl     hGlobals;
  911.     
  912.     // Allocate the driver's global handle 
  913.  
  914.     hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
  915.     anErr = MemError();
  916.     require(anErr == noErr, NewHandleClear);
  917.     
  918.     // Tell the Printing Manager to save our globals handle for us 
  919.     SetMessageHandlerInstanceContext(hGlobals);
  920.  
  921.     return(anErr);
  922.     
  923.     
  924. /******* Clean-up *******/
  925.  
  926. NewHandleClear:
  927.     return(anErr);
  928. }
  929. /* SD_Initialize */
  930.  
  931.  
  932. /****************************************************************************************
  933.  
  934.                             SD_ShutDown
  935.                             
  936.     function:
  937.                 This routine is called when a job-oriented task has completed and the 
  938.                 message chain is being destroyed.  This routine disposes of the driver's
  939.                 globals handle..
  940.                 
  941.     parameters:        
  942.                 None
  943.                 
  944.     returns:
  945.                 OSErr
  946.     
  947. ****************************************************************************************/
  948. OSErr SD_ShutDown(void)
  949. {
  950.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  951.     
  952.     // Dump the draft table if we loaded it
  953.     if ( (*hGlobals)->draftTable != nil )
  954.         DisposHandle((*hGlobals)->draftTable);
  955.     
  956.     // Dump the driver's globals handle if it was allocated 
  957.     if (hGlobals != nil)
  958.         DisposHandle((Handle) hGlobals);
  959.  
  960.     // Make sure the Printing Manager no longer has a reference to our globals handle 
  961.     SetMessageHandlerInstanceContext(nil);
  962.         
  963.     return(noErr);
  964. }
  965. /* SD_ShutDown */
  966.  
  967.  
  968. /****************************************************************************************
  969.  
  970.                             SD_JobFormatDialog
  971.                             
  972.     function:
  973.                 This routine is called when the Printing Manager is called to display the
  974.                 Job Format dialog.  This message gives the driver the opportunity to determine
  975.                 the job format modes that are supported by the application.  If the application
  976.                 supports text, then we set the preferred job format mode to be 'text'.  The preferred
  977.                 format mode is the format mode that becomes active when the user selects Direct
  978.                 Mode from the Job Format dialog box.
  979.                 
  980.     parameters:                
  981.                 dlgResult        result of dismissing the dialog (ok or cancel)
  982.                 
  983.     returns:
  984.                 OSErr
  985.                 
  986. ****************************************************************************************/
  987. OSErr SD_JobFormatDialog(gxDialogResult *dlgResult)
  988. {
  989.     OSErr                         anErr;
  990.     gxJobFormatModeTableHdl    theJobFormatModeList;
  991.     gxJob                             theJob = GXGetJob();
  992.     
  993.     // Did the application specify any job format modes?
  994.     
  995.     anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
  996.     if ( (anErr == noErr) && (theJobFormatModeList != nil) )
  997.     {
  998.         long    i;
  999.  
  1000.         // Examine each job format mode to determine if 'text' mode is supported.  If
  1001.         // it is, then we make it the preferred format mode for Direct Mode printing
  1002.         
  1003.         for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i) 
  1004.         {
  1005.             if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode) 
  1006.             {
  1007.                 // Tell Printing Manger we support 'text' Direct Mode, but that we also
  1008.                 // support other modes.
  1009.                 
  1010.                 GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
  1011.                 break;
  1012.             }
  1013.         }
  1014.         
  1015.         // Dump the temporary handle we were issued
  1016.         DisposHandle((Handle)theJobFormatModeList);
  1017.     }
  1018.         
  1019.     // New we let the dialog be displayed. 
  1020.  
  1021.     anErr = Forward_GXJobDefaultFormatDialog(dlgResult);
  1022.     require(anErr == noErr, Forward_GXJobFormatDialog);
  1023.     
  1024.     return(anErr);
  1025.     
  1026.     
  1027. /******* Clean-up *******/
  1028.  
  1029. Forward_GXJobFormatDialog:
  1030.     return(anErr);
  1031. }
  1032. /* SD_JobFormatDialog */
  1033.  
  1034.  
  1035. /****************************************************************************************
  1036.  
  1037.                             SD_JobPrintDialog
  1038.                             
  1039.     function:
  1040.                 This routine is called when the Printing Manager is called to display the
  1041.                 Job dialog.  This message gives the driver the opportunity to add the LQ Options
  1042.                 panel to the dialog.  This panel provides the user the option to choose between
  1043.                 bidirectional and unidirectional printing.
  1044.                 
  1045.     parameters:                
  1046.                 dlgResult        result of dismissing the dialog (ok or cancel)
  1047.                 
  1048.     returns:
  1049.                 OSErr
  1050.                 
  1051. ****************************************************************************************/
  1052. OSErr SD_JobPrintDialog(gxDialogResult *dlgResult)
  1053. {
  1054.     OSErr                     anErr;
  1055.     gxPanelSetupRecord    thePanelInfo;
  1056.     long                        headMotionSize;
  1057.     Collection                jobCollection;
  1058.     HeadMotionJobItem        theMotion;
  1059.         
  1060.     // Get a reference to the job's collection
  1061.     jobCollection = GXGetJobCollection( GXGetJob() );
  1062.     
  1063.     // See if the head motion collection item exists.  It the item already exists, then
  1064.     // we'll use the last settings.
  1065.  
  1066.     headMotionSize = sizeof(HeadMotionJobItem);
  1067.     anErr = GetCollectionItem (jobCollection,
  1068.                                         kDrvrCreatorType, 
  1069.                                         kHeadMotionItemIndex, 
  1070.                                            &headMotionSize,
  1071.                                            &theMotion);
  1072.                                         
  1073.     if (anErr == collectionItemNotFoundErr)    // T => Item doesn't exist; add it
  1074.     {
  1075.         theMotion.direction = doUnidirectional;
  1076.         
  1077.         anErr = AddCollectionItem(    jobCollection, 
  1078.                                             kDrvrCreatorType, 
  1079.                                             kHeadMotionItemIndex, 
  1080.                                             sizeof(HeadMotionJobItem),
  1081.                                             &theMotion);
  1082.         require(anErr == noErr, AddCollectionItem);
  1083.     }
  1084.     else
  1085.         require(anErr == noErr, CantGetCollection);
  1086.  
  1087.     // Before allowing the Printing Manager to display the dialog, we must first add
  1088.     // our panel to the dialog.  We do this by appropriately filling in the PanelSetupRecord
  1089.     // and then telling the Printing Manager to add our panel to the dialog.
  1090.     
  1091.     // Initialize the dialog panel structure
  1092.     thePanelInfo.panelResId            = kLQOptionsPanl;        //    Resource ID of the 'panl' resource
  1093.     thePanelInfo.resourceRefNum    = GXGetMessageHandlerResFile();
  1094.     thePanelInfo.refCon                = 0;
  1095.     thePanelInfo.panelKind            = gxDriverPanel;
  1096.     
  1097.     // Add the dialog panel to the Print dialog
  1098.     
  1099.     GXSetupDialogPanel(&thePanelInfo);
  1100.     anErr = GXGetJobError( GXGetJob() );
  1101.     require(anErr == noErr, SetupDialogPanel);
  1102.  
  1103.     // Now we let the dialog be displayed. 
  1104.  
  1105.     anErr = Forward_GXJobPrintDialog(dlgResult);
  1106.     check(anErr == noErr);
  1107.     
  1108.     
  1109. /******* Clean-up *******/
  1110.  
  1111. Forward_GXJobPrintDialog:
  1112. SetupDialogPanel:
  1113. CantGetCollection:
  1114. AddCollectionItem:
  1115.     return(anErr);
  1116. }
  1117. /* SD_JobPrintDialog */
  1118.  
  1119.  
  1120. /****************************************************************************************
  1121.  
  1122.                             SD_JobFormatModeQuery
  1123.                             
  1124.     function:
  1125.                 This routine is called when an application calls JobFormatModeQuery to determine
  1126.                 the format modes that are available from the driver.  This message gives the 
  1127.                 driver the opportunity to determine the type of format mode query the driver
  1128.                 is requesting and responds to it with the appropriate data.
  1129.                 
  1130.     parameters:                
  1131.                 theQuery        type of query to perform
  1132.                 srcData        source data (varies depending upon the type of query)
  1133.                 dstData        destination data (varies depending upon the type of query)
  1134.                 
  1135.     returns:
  1136.                 OSErr
  1137.                 
  1138. ****************************************************************************************/
  1139. OSErr SD_JobFormatModeQuery(gxQueryType theQuery, void *srcData, void *dstData)
  1140. {
  1141.     OSErr        anErr = noErr;
  1142.     Handle    theFonts;
  1143.     Handle    theStyles;
  1144.     
  1145.     check(dstData != nil);
  1146.     
  1147.     // What type of query is being requested?
  1148.     switch(theQuery) 
  1149.     {
  1150.         case gxSetStyleJobFormatCommonStyleQuery:
  1151.         {
  1152.             char                *pStyleName;
  1153.  
  1154.             // Fetch the list of supported styles
  1155.             
  1156.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1157.             require(anErr == noErr, FailedToLoadStyles1);
  1158.             
  1159.             HNoPurge(theStyles);
  1160.             HLock(theStyles);
  1161.             
  1162.             // Determine which style is being referenced and set the corresponding style (only 2 styles
  1163.             // are currently supported)
  1164.             
  1165.             if (**((short **) theStyles) == 2)    //    T => We have the correct number of styles
  1166.             {
  1167.                 char        whichFace = 0;
  1168.                 
  1169.                 pStyleName = ((char *) *theStyles) + sizeof(short); 
  1170.                 
  1171.                 if ( IUCompString(pStyleName, (char *) srcData) == 0 )    //    T => They want bold face
  1172.                 {
  1173.                     whichFace = bold;
  1174.                 }
  1175.                 else
  1176.                 {
  1177.                     // Point to the next name in the list
  1178.                     pStyleName += *pStyleName + 1;
  1179.  
  1180.                     if ( IUCompString(pStyleName, (char *) srcData) == 0 )    //    T => They want underline face
  1181.                     {
  1182.                         whichFace = underline;
  1183.                     }
  1184.                 }
  1185.  
  1186.                 //    If the client specified a valid face, set it now
  1187.                 if (whichFace != 0)
  1188.                 {
  1189.                     SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
  1190.                 }
  1191.             }
  1192.             // else - something is wrong with our resource
  1193.             
  1194.             // Dump the temporary handle
  1195.             DisposHandle(theStyles);
  1196.             
  1197.             break;
  1198.         }
  1199.             
  1200.         case gxGetJobFormatFontCommonStylesQuery:
  1201.         {
  1202.             short                numStyles;
  1203.             short                i;
  1204.             char                *pStyleName;
  1205.  
  1206.             // Fetch the list of supported styles
  1207.             
  1208.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1209.             require(anErr == noErr, FailedToLoadStyles2);
  1210.             
  1211.             HNoPurge(theStyles);
  1212.             HLock(theStyles);
  1213.             
  1214.             // Determine the number of styles in the list
  1215.             numStyles = **((short **) theStyles);
  1216.  
  1217.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the styles
  1218.                 SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1219.             else
  1220.                 *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1221.             
  1222.             anErr = MemError();
  1223.             require(anErr == noErr, StyleTableResizeFailed);
  1224.             
  1225.             // Now extract the name of each of the supported fonts
  1226.             
  1227.             for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
  1228.             {
  1229.                 BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
  1230.             }
  1231.             
  1232.             (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
  1233.             
  1234.             // Dump the temporary handle
  1235.             DisposHandle(theStyles);
  1236.             
  1237.             break;
  1238.         }
  1239.             
  1240.         case gxGetJobFormatLineConstraintQuery:            //    This type of query is not supported
  1241.             if (*(Handle *)dstData != nil)
  1242.                 SetHandleSize(*(Handle *)dstData, 0);        // Don't return any data
  1243.             break;
  1244.             
  1245.         case gxGetJobFormatFontsQuery:
  1246.         {
  1247.             short                numFonts;
  1248.             short                i;
  1249.             char                *pFontName;
  1250.  
  1251.             // Fetch the list of supported fonts
  1252.             
  1253.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
  1254.             require(anErr == noErr, FailedToLoadFonts);
  1255.             
  1256.             HNoPurge(theFonts);
  1257.             HLock(theFonts);
  1258.             
  1259.             // Determine the number of fonts in the list
  1260.             numFonts = **((short **) theFonts);
  1261.  
  1262.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the fonts
  1263.                 SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1264.             else
  1265.                 *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1266.             
  1267.             anErr = MemError();
  1268.             require(anErr == noErr, FontTableResizeFailed);
  1269.             
  1270.             // Now generate a reference to each of the supported fonts
  1271.             
  1272.             for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
  1273.             {
  1274.                 gxFont            thisFont;
  1275.                 gxFontTable    *pFontTable;
  1276.             
  1277.                 thisFont = FindPNameFont(gxFullFontName, pFontName);
  1278.                 
  1279.                 pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
  1280.                 pFontTable->fonts[i - 1] = thisFont;
  1281.             }
  1282.             
  1283.             (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
  1284.             
  1285.             // Dump the temporary handle
  1286.             DisposHandle(theFonts);
  1287.  
  1288.             break;
  1289.         }
  1290.             
  1291.         case gxGetJobFormatFontConstraintQuery:
  1292.         {
  1293.             gxPositionConstraintTable        *pPositionTable;
  1294.             
  1295.             if ( *(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on position constraints
  1296.                 SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
  1297.             else
  1298.                 *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
  1299.             
  1300.             pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
  1301.             
  1302.             pPositionTable->phase.x     = 0;                //    Start at the top left corner of the page
  1303.             pPositionTable->phase.y     = 0;
  1304.             pPositionTable->offset.x     = ff(12);        // Indent from the top left by a six lines per inch margin
  1305.             pPositionTable->offset.y     = ff(12);         
  1306.             pPositionTable->numSizes     = 2;                // Two font sizes supported
  1307.             pPositionTable->sizes[0]     = ff(10);         // 10 pitch
  1308.             pPositionTable->sizes[1]     = ff(12);         // 12 pitch
  1309.             
  1310.             break;
  1311.         }
  1312.     } // switch
  1313.     
  1314.     return(anErr);
  1315.     
  1316.  
  1317. /******* Clean-up *******/
  1318.  
  1319. StyleTableResizeFailed:
  1320.     DisposHandle((Handle) theStyles);
  1321.     return(anErr);
  1322.  
  1323. FontTableResizeFailed:
  1324.     DisposHandle((Handle) theFonts);
  1325.  
  1326. FailedToLoadStyles1:
  1327. FailedToLoadStyles2:
  1328. FailedToLoadFonts:
  1329.     return(anErr);
  1330. }
  1331. /* SD_JobFormatModeQuery */
  1332.  
  1333.  
  1334. /****************************************************************************************
  1335.  
  1336.                             SD_OpenConnection
  1337.                             
  1338.     function:
  1339.                 This routine is called when the Printing Manager sends the OpenConnection
  1340.                 message.  We take this opportunity to open a connection to the printer and
  1341.                 query the printer to determine its configuration (e.g. color ribbon, trays, etc.).
  1342.                 We then save the configuration information in the desktop printer file.
  1343.                 
  1344.     parameters:        
  1345.                 None
  1346.                 
  1347.     returns:
  1348.                 OSErr
  1349.     
  1350. ****************************************************************************************/
  1351. OSErr SD_OpenConnection(void)
  1352. {
  1353.     OSErr                anErr;
  1354.  
  1355.     // Try to open the connection
  1356.     
  1357.     anErr = Forward_GXOpenConnection();
  1358.     require(anErr == noErr, Forward_GXOpenConnection);
  1359.     
  1360.     // Query the printer so we can update the configuration information
  1361.     
  1362.     anErr = UpdateDTPConfigInfo();
  1363.     require(anErr == noErr, UpdateDTPConfigInfo);
  1364.     
  1365.     return(anErr);
  1366.     
  1367.     
  1368. /******* Clean-up *******/
  1369.  
  1370. UpdateDTPConfigInfo:
  1371.     Send_GXCleanupOpenConnection();
  1372.     
  1373. Forward_GXOpenConnection:
  1374.     return(anErr);
  1375. }
  1376. /* SD_OpenConnection */
  1377.  
  1378.  
  1379. /****************************************************************************************
  1380.  
  1381.                             SD_CleanupOpenConnection
  1382.                             
  1383.     function:
  1384.                 This routine is called when the Printing Manager sends the CleanupOpenConnection
  1385.                 message.  It's initiated by our SD_OpenConnection routine when we cannot query
  1386.                 the printer after opening the connection.  We simply forward the message along to
  1387.                 allow others in the message chain to cleanup.
  1388.                 
  1389.     parameters:        
  1390.                 None
  1391.                 
  1392.     returns:
  1393.                 OSErr
  1394.     
  1395. ****************************************************************************************/
  1396. void SD_CleanupOpenConnection(void)
  1397. {
  1398.     // Just forward along the message
  1399.     Forward_GXCleanupOpenConnection();
  1400. }
  1401. /* SD_CleanupOpenConnection */
  1402.  
  1403.  
  1404. /****************************************************************************************
  1405.  
  1406.                             SD_StartSendPage
  1407.                             
  1408.     function:
  1409.                 This routine is called by the Printing Manager to signal the start of sending
  1410.                 a new page to the printer.  If it's a manual feed job, then we alert the user
  1411.                 to make sure the paper is in the printer.  If the printer has trays attached,
  1412.                 then this routine determines from which tray to feed the paper and then sends
  1413.                 the appropriate tray selection command to the printer.  The tray to pull the
  1414.                 paper from has already been determined by this time by the Universal Driver.
  1415.                 The Job collection contains the index of the tray to pull from.
  1416.                 
  1417.     parameters:                
  1418.                 pageFormat        format for the page to print
  1419.  
  1420.     returns:
  1421.                 OSErr
  1422.     
  1423. ****************************************************************************************/
  1424. OSErr SD_StartSendPage (gxFormat pageFormat)
  1425. {
  1426.     OSErr                    anErr;
  1427.     Collection            jobCollection;
  1428.     gxStatusRecord        *pStatus;
  1429.     gxTrayFeedInfo        trayFeedInfo;
  1430.     long                    itemSize = sizeof(trayFeedInfo);
  1431.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1432.     
  1433.     // Get a reference to the job's collection
  1434.     jobCollection = GXGetJobCollection( GXGetJob() );
  1435.     
  1436.     // Determine if this is a manual feed page 
  1437.  
  1438.     anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1439.     nrequire(anErr, GetCollectionItem);
  1440.     
  1441.     if (trayFeedInfo.manualFeedThisPage)    //    T => Alert the user to place the paper into the printer
  1442.     {
  1443.         gxManualFeedRecord    *mfeedInfo;
  1444.         gxPaperType                thePaperType;
  1445.  
  1446.         // Wait for all IO to complete, so that we can correctly tell the user what to do.
  1447.         // Since the WriteData message makes sure all data is flushed before performing the
  1448.         // IO, this call insures that pending IO is complete.
  1449.  
  1450.         anErr = Send_GXWriteData(nil, 0);
  1451.         nrequire(anErr, FlushAllData);
  1452.  
  1453.         // Now we set-up to alert the user to put paper into the printer
  1454.     
  1455.         pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + sizeof(gxManualFeedRecord));
  1456.         anErr = MemError();
  1457.         require(anErr == noErr, NewPtrClear);
  1458.     
  1459.         // Initialize the appropriate fields within the status record 
  1460.         
  1461.         pStatus->statusOwner        = 'univ';
  1462.         pStatus->statResId         = gxUnivAlertStatusResourceId;
  1463.         pStatus->statResIndex     = gxUnivManualFeedIndex;
  1464.         pStatus->bufferLen         = sizeof(gxManualFeedRecord);
  1465.  
  1466.         mfeedInfo = (gxManualFeedRecord *) &pStatus->statusBuffer;
  1467.         mfeedInfo->canAutoFeed = true;
  1468.         GXGetPaperTypeName(thePaperType = GXGetFormatPaperType(pageFormat), mfeedInfo->paperTypeName);
  1469.  
  1470.         // Now display the alert to the user. Continue alerting until the user clicks OK, he cancels
  1471.         // printing, or some other fatal error happens
  1472.         do
  1473.         {
  1474.             // Issue the alert to the user
  1475.             anErr = GXAlertTheUser(pStatus);
  1476.         }
  1477.         while ( (anErr == noErr) && (pStatus->dialogResult == nil) );
  1478.         
  1479.         // Based upon the users response, we continue, cancel, or switch to auto-feed
  1480.         
  1481.         switch (pStatus->dialogResult)
  1482.         {
  1483.             case ok:                        // Assume the user loaded the paper 
  1484.                 break;
  1485.                 
  1486.             case cancel:                // User cancelled the job; make sure the error code is set
  1487.                 anErr = gxPrUserAbortErr;
  1488.                 break;
  1489.                 
  1490.             case gxAutoFeedButtonId:    // User wishes to do the remainder of the job with auto-feed. Update job to 
  1491.                                             // reflect auto-feed. 
  1492.                 
  1493.                 {
  1494.                 gxPaperFeedInfo paperFeed;
  1495.                 
  1496.                 /* Update for job */
  1497.                 paperFeed.autoFeed = true;
  1498.                 (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
  1499.                 }
  1500.                 
  1501.                 /* Update as it may be reused */
  1502.                 trayFeedInfo.manualFeedThisPage = false;    /* Other trayInfo fields are still valid */
  1503.                 (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
  1504.                 
  1505.                 /* Can pass paper type reference as this IS device communication time */
  1506.                 anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
  1507.                 ncheck(anErr);
  1508.                 
  1509.                 /* Update gxTrayFeedInfo.feedTrayIndex for below */
  1510.                 itemSize = sizeof(trayFeedInfo);
  1511.                 if (! anErr)
  1512.                     anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1513.                 break;
  1514.         }
  1515.         
  1516.         // Dump the status record
  1517.         DisposPtr((Ptr) pStatus);
  1518.     }
  1519.     
  1520.     require(anErr == noErr, UserAborted);
  1521.     
  1522.     // At this point we determine if there are trays attached, and if so, we need
  1523.     // to issue a command to the printer to select from the proper tray.
  1524.     
  1525.     if ( PrinterHasTrays() > 0 )    //    T => Printer does have trays attached
  1526.     {
  1527.         gxTrayIndex                whichTray;
  1528.         char                        cmndBuff[3];
  1529.         TraySettingsJobItem    oldAppTraySettings;
  1530.         
  1531.         // We first determine if we're printing from an old application or a new application because
  1532.         // the setting of which tray to use will be determined from different information. To see if
  1533.         // we are printing an old app. document, we look for the kTraySettingsItemIndex collection item.
  1534.         
  1535.         itemSize = sizeof(TraySettingsJobItem);
  1536.         if ( GetCollectionItem( GXGetJobCollection(GXGetJob()), kDrvrCreatorType, kTraySettingsItemIndex, &itemSize, &oldAppTraySettings) == noErr )
  1537.         {
  1538.             if ( (*hGlobals)->pagePrinting == 1 )    //    T => Printing the first page
  1539.             {
  1540.                 whichTray = oldAppTraySettings.firstPageFromTray - 1;        //    Must be zero based
  1541.             }
  1542.             else    //    T => Printing some other page
  1543.             {
  1544.                 whichTray = oldAppTraySettings.remainingFromTray - 1;        //    Must be zero based
  1545.             }
  1546.         }
  1547.         else    //    T => New app so get tray settings from the 'tray' collection item
  1548.         {
  1549.             // The trayFeedInfo specifies which tray to select the paper from.
  1550.             whichTray = trayFeedInfo.feedTrayIndex - 1;        // Must be zero based
  1551.         }
  1552.         
  1553.         // Compose the tray selection command
  1554.         
  1555.         cmndBuff[0] = kEscape;
  1556.         cmndBuff[1] = '@';
  1557.         cmndBuff[2] = whichTray + 0x30;        // Force to an ACSII number
  1558.         
  1559.         // Send the command to the printer
  1560.         anErr = Send_GXBufferData(cmndBuff, 3, gxNoBufferOptions);
  1561.         require(anErr == noErr, BufferData);        
  1562.     }
  1563.     
  1564.     // Update the status information to tell the user that we're sending data to the printer
  1565.     
  1566.     anErr = GXReportStatus(kDriverStatusID, kSendingPartOfPageStatIdx);
  1567.     require(anErr == noErr, ReportStatus);
  1568.  
  1569.     // Now forward the message to others in the chain
  1570.     
  1571.     anErr = Forward_GXStartSendPage(pageFormat);
  1572.     check(anErr == noErr);
  1573.     
  1574.     
  1575. /******* Cleanup *******/
  1576.  
  1577. ReportStatus:
  1578. BufferData:
  1579. UserAborted:
  1580. NewPtrClear:
  1581. FlushAllData:
  1582. GetCollectionItem:
  1583.     return(anErr);
  1584. }
  1585. /* SD_StartSendPage */
  1586.  
  1587.  
  1588. /****************************************************************************************
  1589.  
  1590.                             SD_ImagePage
  1591.                             
  1592.     function:
  1593.                 This routine is called by the Printing Manager to signal the start of imaging
  1594.                 a new page to the printer.  We take this opportunity to remember which page is
  1595.                 being printed.  This inforamtion is later used by SD_StartSendPage to control
  1596.                 the input tray selection for documents which are printed from old applications.
  1597.                 
  1598.     parameters:                
  1599.                 theFormat        format for the page being rendered
  1600.                 theShape            shape representing the page
  1601.                 pageInfo            information about the page being rendered
  1602.                 imageData        pointer to the raster image data
  1603.  
  1604.     returns:
  1605.                 OSErr
  1606.     
  1607. ****************************************************************************************/
  1608. OSErr SD_ImagePage (    gxSpoolFile                theFile, 
  1609.                             long                         pageNumber, 
  1610.                             gxFormat                    theFormat, 
  1611.                             gxRasterImageDataHdl    imageData)
  1612. {
  1613.     OSErr                    anErr;
  1614.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1615.  
  1616.     // Remember which page of the document we're currently imaging
  1617.     (*hGlobals)->pagePrinting = pageNumber;
  1618.     
  1619.     // Send the message along to others in the chain
  1620.     anErr = Forward_GXImagePage(theFile, pageNumber, theFormat, imageData);
  1621.     check(anErr == noErr);
  1622.     
  1623.     return(anErr);
  1624. }
  1625. /* SD_ImagePage */
  1626.  
  1627.  
  1628. /****************************************************************************************
  1629.  
  1630.                             SD_RenderPage
  1631.                             
  1632.     function:
  1633.                 This routine is called by the Printing Manager to signal the start of sending
  1634.                 a new page to the printer.  If it's a manual feed job, then we alert the user
  1635.                 to make sure the paper is in the printer.  Next we set the printer's left margin
  1636.                 and then we're set to begin printing the page.
  1637.                 
  1638.     parameters:                
  1639.                 theFormat        format for the page being rendered
  1640.                 theShape            shape representing the page
  1641.                 pageInfo            information about the page being rendered
  1642.                 imageData        pointer to the raster image data
  1643.  
  1644.     returns:
  1645.                 OSErr
  1646.     
  1647. ****************************************************************************************/
  1648. OSErr SD_RenderPage (gxFormat                        theFormat, 
  1649.                             gxShape                        thePage, 
  1650.                             gxPageInfoRecord            *pageInfo, 
  1651.                             gxRasterImageDataHdl     imageData)
  1652. {
  1653.     OSErr                    anErr;
  1654.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1655.     gxRectangle            paperSize;
  1656.     
  1657.     // Find out how big our paper is
  1658.     GXGetFormatDimensions(theFormat, nil, &paperSize);
  1659.     
  1660.     // Determine the left margin (in pixels)
  1661.     {
  1662.         SpecGlobalsPtr            pGlobals;
  1663.         gxRasterImageDataPtr    pImageData;
  1664.  
  1665.         pImageData = *imageData;
  1666.         pGlobals = *hGlobals;
  1667.         if ( -(paperSize.left) < ff(18) )    // T => IW LQ's can't go tighter than .25 inch
  1668.             paperSize.left = -(ff(18));        
  1669.         
  1670.         pGlobals->leftMargin = FixedToInt( FixMul(-paperSize.left, FixDiv(pImageData->hImageRes, ff(72)) ) );
  1671.     }
  1672.  
  1673.     // If not text mode, image the page the normal raster way (via SD_RasterPackageBitmap).  We
  1674.     // must however set the size of the page and position the paper (with line feeds) to get to
  1675.     // the proper "top-of-form".
  1676.     
  1677.     if ( GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode ) 
  1678.     {
  1679.         Str255            formStrLength;            // should be more than big enough for form skipping
  1680.         char                aNumber[8];
  1681.         char                len = 0;
  1682.         short                formLen;                // form length (in 144 dpi)
  1683.         short                i;
  1684.         
  1685.         // Force the current line position to be the top of form (assumes the user has positioned the 
  1686.         // paper properly by this time)
  1687.         
  1688.         formStrLength[len++] = kEscape;
  1689.         formStrLength[len++] = 'v';
  1690.  
  1691.         // Now we want to skip down the page past the top margin.  This will put us in a position to
  1692.         // output the first bands of data.
  1693.         
  1694.         formLen = FixedToInt( FixMul(-paperSize.top, ff(2)) );                    // length is set in 144 dpi
  1695.         if (formLen > 0)
  1696.         {
  1697.             // send multiples of 99 since this is the maximum line feed spacing we can have
  1698.             if (formLen >= 99)
  1699.             {
  1700.                 formStrLength[len++] = kEscape;
  1701.                 formStrLength[len++] = 'T';
  1702.                 formStrLength[len++] = '9';
  1703.                 formStrLength[len++] = '9';
  1704.                 do
  1705.                 {
  1706.                     formStrLength[len++] = kLineFeed;        // line feed
  1707.                     
  1708.                     formLen -= 99;
  1709.                 }
  1710.                 while (formLen >= 99);
  1711.             }
  1712.                 
  1713.             // Send remaining line feeds to position to the top of the printable page
  1714.             if (formLen > 0)
  1715.             {
  1716.                 formStrLength[len++] = kEscape;
  1717.                 formStrLength[len++] = 'T';
  1718.                 NumToString(formLen, aNumber);
  1719.                 if ( StrLength(aNumber) == 1 )
  1720.                 {
  1721.                     formStrLength[len++] = '0';
  1722.                     formStrLength[len++] = aNumber[1];
  1723.                 }
  1724.                 else
  1725.                 {
  1726.                     formStrLength[len++] = aNumber[1];
  1727.                     formStrLength[len++] = aNumber[2];
  1728.                 }
  1729.                 formStrLength[len++] = kLineFeed;        // line feed
  1730.             }
  1731.         }
  1732.         
  1733.         // Now we must specify the paper length based upon the paper size asociated with the format
  1734.         
  1735.         formStrLength[len++] = kEscape;
  1736.         formStrLength[len++] = 'H';
  1737.  
  1738.         formLen = FixedToInt( FixMul(paperSize.bottom - paperSize.top, ff(2)) );    // length is set in 144 dpi
  1739.         NumToString(formLen, aNumber);
  1740.         for (i = 0; i < 4-aNumber[0]; ++i)
  1741.             formStrLength[len++] = '0';
  1742.         for (i = 1; i <= aNumber[0]; ++i)
  1743.             formStrLength[len++] = aNumber[i];
  1744.  
  1745.         // Send out the line feeds and the paper size specifier
  1746.         anErr = Send_GXBufferData(&formStrLength[0], len, gxNoBufferOptions);
  1747.         require(anErr == noErr, SetFormStrLength);        
  1748.     
  1749.         // Now forward the message to others in the chain
  1750.         
  1751.         anErr = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageData);
  1752.         require(anErr == noErr, Forward_GXRenderPage);
  1753.     } 
  1754.     else    //    T => Doing draft (i.e. direct mode) print job; we do all the rendering
  1755.     {
  1756.         anErr = PrintPageInDraftMode(thePage, imageData);
  1757.     }
  1758.     
  1759.     
  1760. /******* Cleanup *******/
  1761.  
  1762. SetFormStrLength:
  1763. Forward_GXRenderPage:
  1764.     return(anErr);
  1765. }
  1766. /* SD_RenderPage */
  1767.  
  1768.  
  1769. /****************************************************************************************
  1770.  
  1771.                             SD_DefaultPrinter
  1772.                             
  1773.     function:
  1774.                 This routine is called when a new printer object is being created as a
  1775.                 result of someone having called NewJob.  This message gives the driver the
  1776.                 opportunity to add any information we want to the new printer object.  In
  1777.                 this case, we add a new black and white viewDevice to the printer object 
  1778.                 which will allow the client application to format a document for this 
  1779.                 specific device at 216 dpi.  If the printer has a color ribbon attachment,
  1780.                 then we create a second view device at 216 dpi which supports eight
  1781.                 colors.
  1782.                 
  1783.     parameters:                
  1784.                 thePrinter        the newly allocated printer object
  1785.                 
  1786.     returns:
  1787.                 OSErr
  1788.                 
  1789. ****************************************************************************************/
  1790. OSErr SD_DefaultPrinter(gxPrinter thePrinter)
  1791. {
  1792.     OSErr             anErr;
  1793.     gxSetColor        theColors[8];
  1794.     gxSetColor        *pColor;
  1795.     
  1796.     // First we let others in the chain default the printer object before we do. 
  1797.  
  1798.     anErr = Forward_GXDefaultPrinter(thePrinter);
  1799.     require(anErr == noErr, Forward_GXDefaultPrinter);
  1800.     
  1801.     // Add the standard black and white view device to the printer object
  1802.     
  1803.     // First set up the color set
  1804.     pColor = &theColors[0];
  1805.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;            // white 
  1806.     pColor++;
  1807.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;            // black 
  1808.     
  1809.     // Now add the view device
  1810.     anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 2);
  1811.     require(anErr == noErr, MakeBWViewDevice);
  1812.     
  1813.     // Does the printer have a color ribbon installed?
  1814.     if ( PrinterHasColorRibbon() )
  1815.     {
  1816.         // Add the standard color view device to the printer object
  1817.         
  1818.         // First set up the color set
  1819.         //
  1820.         //    Color            Index        R                G                B
  1821.         //    white            0            0xFFFF        0xFFFF        0xFFFF        
  1822.         //    yellow        1            0xFFFF        0xFFFF        0x0000
  1823.         //    magenta        2            0xFFFF        0x0000        0xFFFF
  1824.         //    red            3            0xFFFF        0x0000        0x0000
  1825.         //    cyan            4            0x0000        0xFFFF        0xFFFF
  1826.         //    green            5            0x0000        0xFFFF        0x0000
  1827.         //    blue            6            0x0000        0x0000        0xFFFF
  1828.         //    black            7            0x0000        0x0000        0x0000
  1829.  
  1830.         pColor = &theColors[0];
  1831.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;                pColor++;        // white 
  1832.         pColor->rgb.red = pColor->rgb.green = 0xFFFF; pColor->rgb.blue = 0x0000;    pColor++;        // yellow 
  1833.         pColor->rgb.red = pColor->rgb.blue = 0xFFFF; pColor->rgb.green = 0x0000;    pColor++;        // magenta 
  1834.         pColor->rgb.red =0xFFFF;  pColor->rgb.blue = pColor->rgb.green = 0x0000;    pColor++;        // red 
  1835.         pColor->rgb.green = pColor->rgb.blue = 0xFFFF; pColor->rgb.red = 0x0000;    pColor++;        // cyan 
  1836.         pColor->rgb.red = pColor->rgb.blue = 0x0000; pColor->rgb.green = 0xFFFF;    pColor++;        // green 
  1837.         pColor->rgb.red = pColor->rgb.green = 0x0000; pColor->rgb.blue = 0xFFFF;    pColor++;        // blue 
  1838.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;                                    // black 
  1839.         
  1840.         // Now add the view device
  1841.         anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 8);
  1842.         require(anErr == noErr, MakeColorViewDevice);
  1843.     }
  1844.     
  1845. /******* Clean-up *******/
  1846.  
  1847. MakeColorViewDevice:
  1848. MakeBWViewDevice:
  1849. Forward_GXDefaultPrinter:
  1850.     return(anErr);
  1851. }
  1852. /* SD_DefaultPrinter */
  1853.  
  1854. /****************************************************************************************
  1855.  
  1856.                             SD_DefaultFormat
  1857.                             
  1858.     function:
  1859.                 This routine is called when a new format is being created as a result of someone
  1860.                 having called NewFormat.  It is also called to sync up the viewDevices with the
  1861.                 collection's quality mode.
  1862.                 
  1863.     parameters:                
  1864.                 theFormat        the format being defaulted
  1865.                 
  1866.     returns:
  1867.                 OSErr
  1868.                 
  1869. ****************************************************************************************/
  1870. OSErr SD_DefaultFormat(gxFormat theFormat)
  1871. {
  1872.     OSErr                anErr;
  1873.     Handle             jobQualitySettingsHdl;    
  1874.     
  1875.     anErr = Forward_GXDefaultFormat(theFormat);
  1876.     
  1877.     // now, if the application has set up a special formatting mode, we need to update
  1878.     // the quality mode collection item (and any private ones we use)
  1879.     if (anErr == noErr)
  1880.         {
  1881.         gxPoint                    dpiPoint = {ff(72), ff(72)};
  1882.         gxMapping                vdMapping;
  1883.         gxViewDevice            selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
  1884.         
  1885.         if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
  1886.             {
  1887.             GXGetViewDeviceMapping(selectedDevice, &vdMapping);
  1888.             MapPoints(&vdMapping, 1, &dpiPoint);
  1889.             
  1890.             {
  1891.             gxQualityInfo        *qualitySettings;
  1892.             Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1893.     
  1894.             jobQualitySettingsHdl = NewHandle(0);
  1895.             anErr = MemError();
  1896.             nrequire(anErr, FailedNewHandle);
  1897.  
  1898.             anErr = GetCollectionItemHdl (     jobCollection,
  1899.                                                         gxQualityTag,
  1900.                                                          gxPrintingTagID,
  1901.                                                        jobQualitySettingsHdl );
  1902.  
  1903.             if (anErr == collectionItemNotFoundErr) 
  1904.                 {
  1905.                 Str255            bestString, roughString;
  1906.                 Size                count1, count2;
  1907.                 Ptr                p;
  1908.         
  1909.                 GetIndString( bestString, kQualityID, kBestString);
  1910.                 GetIndString( roughString, kQualityID, kRoughString);
  1911.  
  1912.                 SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
  1913.                 anErr = MemError();
  1914.                 nrequire( anErr, FailedSetHandleSize );
  1915.                         
  1916.                 qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1917.                 
  1918.                 qualitySettings->disableQuality = false;
  1919.                 qualitySettings->defaultQuality = 1;
  1920.                 qualitySettings->currentQuality = 1;
  1921.                 qualitySettings->qualityCount = 2;
  1922.         
  1923.                 count1 = bestString[0]+1;
  1924.                 p = qualitySettings->qualityNames;
  1925.                 BlockMove( bestString, p, count1 );
  1926.         
  1927.                 count2 = roughString[0]+1;
  1928.                 p += count1;
  1929.                 BlockMove( roughString, p, count2 );
  1930.         
  1931.                 }
  1932.             else
  1933.                 qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1934.  
  1935.             qualitySettings->currentQuality = 
  1936.                 (dpiPoint.y > ff(200)) ? (qualitySettings->qualityCount-1) : 0;
  1937.  
  1938.             anErr = AddCollectionItemHdl (     jobCollection,
  1939.                                                         gxQualityTag,
  1940.                                                         gxPrintingTagID,
  1941.                                                         jobQualitySettingsHdl );
  1942.                                                  
  1943.             if (anErr == noErr)
  1944.                 (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
  1945.                 
  1946.             DisposHandle(jobQualitySettingsHdl);
  1947.             }
  1948.             
  1949.             }
  1950.  
  1951.         }
  1952.         
  1953. FailedNewHandle:        
  1954.     return(anErr);
  1955.  
  1956. FailedSetHandleSize:
  1957.     DisposHandle(jobQualitySettingsHdl);
  1958.     return(anErr);
  1959.     
  1960. /* SD_DefaultFormat */
  1961.  
  1962. /****************************************************************************************
  1963.  
  1964.                             SD_DefaultJob
  1965.                             
  1966.     function:
  1967.                 This routine is called when a new job is being created as a result of someone
  1968.                 having called NewJob.  The driver takes this opportunity to add a default
  1969.                 head motion collection item to the job.
  1970.                 
  1971.     parameters:                
  1972.                 theJob        the job being defaulted
  1973.                 
  1974.     returns:
  1975.                 OSErr
  1976.                 
  1977. ****************************************************************************************/
  1978. OSErr SD_DefaultJob()
  1979. {
  1980.     OSErr        anErr;
  1981.     gxJob     theJob = GXGetJob();
  1982.     
  1983.     // First forward the default job message along
  1984.     anErr = Forward_GXDefaultJob();
  1985.     require(anErr == noErr, Forward_GXDefaultJob);
  1986.     
  1987.     // Add the default collection item which specifies the desired head motion.
  1988.     {
  1989.         HeadMotionJobItem        theMotion;
  1990.         
  1991.         theMotion.direction = doUnidirectional;
  1992.         
  1993.         anErr = AddCollectionItem(    GXGetJobCollection(theJob), 
  1994.                                             kDrvrCreatorType, 
  1995.                                             kHeadMotionItemIndex, 
  1996.                                             sizeof(HeadMotionJobItem),
  1997.                                             &theMotion);
  1998.         check(anErr == noErr);
  1999.     }
  2000.  
  2001.  
  2002. /******* Clean-up *******/
  2003.  
  2004. Forward_GXDefaultJob:
  2005.     return(anErr);
  2006. }
  2007. /* SD_DefaultJob */
  2008.  
  2009.  
  2010. /****************************************************************************************
  2011.  
  2012.                             SD_SetupImageData
  2013.                             
  2014.     function:
  2015.                 This routine is called when the Printing Manager wants us to initialize any
  2016.                 constant data that's used to image the entire job.  This driver takes this
  2017.                 opportunity to massage the raster image data 
  2018.                 
  2019.     parameters:                
  2020.                 hImageData        Handle to the raster imaging data
  2021.     returns:
  2022.                 OSErr
  2023.     
  2024. ****************************************************************************************/
  2025. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  2026. {
  2027.     OSErr                        anErr;
  2028.     Boolean                     isJobNotFinalQuality;
  2029.     Boolean                    isTextJobFormatMode;
  2030.     gxRasterImageDataPtr    pImageData;
  2031.     HeadMotionJobItem        theMotion;
  2032.     long                        headMotionSize;
  2033.     gxJob                        theJob = GXGetJob();
  2034.  
  2035.     // Let others in the message chain do their SetupImageData function 
  2036.     anErr = Forward_GXSetupImageData(hImageData);
  2037.     require(anErr == noErr, Forward_GXSetupImageData);
  2038.     
  2039.     // Determine if we're to do "final" quality
  2040.     isJobNotFinalQuality = !JobIsBestQuality();
  2041.     
  2042.     // Fetch the head motion job collection item to determine the head motion we should be using
  2043.  
  2044.     headMotionSize = sizeof(HeadMotionJobItem);
  2045.     anErr = GetCollectionItem (GXGetJobCollection(theJob),
  2046.                                         kDrvrCreatorType,
  2047.                                         kHeadMotionItemIndex,
  2048.                                         &headMotionSize,
  2049.                                         &theMotion);
  2050.     check(anErr == noErr);
  2051.     
  2052.     if (anErr != noErr)    //    T => Default to unidirectional printing => better quality
  2053.     {
  2054.         theMotion.direction = doUnidirectional;
  2055.         anErr = noErr;
  2056.     }
  2057.  
  2058.     // Determine if we are to perform draft mode printing
  2059.     isTextJobFormatMode = ( GXGetJobFormatMode(theJob) == gxTextJobFormatMode );
  2060.     
  2061.     // If the job is not final quality or using textJobFormatMode, downgrade the imaging data to lower quality
  2062.     if (isJobNotFinalQuality || isTextJobFormatMode)
  2063.     {
  2064.         pImageData = *hImageData;
  2065.                 
  2066.         // Image at 72 dpi
  2067.         pImageData->hImageRes = ff(72);
  2068.         pImageData->vImageRes = ff(72);
  2069.         
  2070.         // If we're in draft mode, we need to load the draft table to know how to print all possible characters
  2071.         if (isTextJobFormatMode)
  2072.         {
  2073.             Handle                draftTable;
  2074.             SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  2075.         
  2076.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
  2077.             require(anErr == noErr, FailedToLoadDraftTable);
  2078.             
  2079.             // Save the draft table handle in our globals
  2080.             (*hGlobals)->draftTable = draftTable;
  2081.         }
  2082.         else    //    T => We need to setup better low resolution halftones
  2083.         {
  2084.             short    plane;
  2085.             
  2086.             // Use halftones that will look better at 72 dpi resolution than our default values.
  2087.             
  2088.             // Use the same angle and frequency for all planes, because orderDitherDot
  2089.             // won't moire on us
  2090.             for (plane = 0; plane < 4; ++plane)
  2091.             {
  2092.                 pImageData->theSetup.planeSetup[plane].planeHalftone.angle = ff(0);
  2093.                 pImageData->theSetup.planeSetup[plane].planeHalftone.frequency = ff(9);
  2094.                 pImageData->theSetup.planeSetup[plane].planeHalftone.method = gxDispersedDot;
  2095.             }
  2096.         }
  2097.         
  2098.         // Determine the StartSendPage command string to use depending upon whether the user choose birdirectional or
  2099.         // unidirectional motion.
  2100.         
  2101.         if (isJobNotFinalQuality)
  2102.         {
  2103.             // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
  2104.             // or unidirectional string)
  2105.             
  2106.             if ( theMotion.direction == doUnidirectional )
  2107.                 pImageData->packageControls.startPageStringID = kLowResUniDirID;
  2108.             else
  2109.                 pImageData->packageControls.startPageStringID = kLowResBiDirID;
  2110.         }
  2111.         
  2112.         // Update the packaging data to reflect the lower resolution
  2113.         pImageData->packagingInfo.headHeight         = 8;        // 8 pins (instead of 24)
  2114.         pImageData->packagingInfo.numberPasses     = 1;        // in 1 head pass
  2115.         pImageData->packagingInfo.passOffset         = 0;        // with no space between passes
  2116.     }
  2117.     else    //    T => Final quality job
  2118.     {
  2119.         pImageData = *hImageData;
  2120.                 
  2121.         // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
  2122.         // or unidirectional string)
  2123.         
  2124.         if ( theMotion.direction == doUnidirectional )
  2125.             pImageData->packageControls.startPageStringID = kHighResUniDirID;
  2126.         else
  2127.             pImageData->packageControls.startPageStringID = kHighResBiDirID;
  2128.  
  2129.         // image at 216 dpi
  2130.         pImageData->hImageRes = ff(216);
  2131.         pImageData->vImageRes = ff(216);
  2132.     }
  2133.     
  2134.     // If the printer doesn't have a color ribbon, set up for black and white printing
  2135.     if ( !PrinterHasColorRibbon() )
  2136.     {
  2137.         pImageData = *hImageData;
  2138.  
  2139.         // one plane, no color flags, move the halftone info up into correct position
  2140.         pImageData->theSetup.planes = 1;
  2141.         pImageData->packagingInfo.colorPasses = 1;
  2142.         pImageData->packagingInfo.packageOptions = 0;
  2143.         pImageData->theSetup.planeSetup[0] = pImageData->theSetup.planeSetup[3];
  2144.         pImageData->theSetup.planeSetup[0].planeHalftone.tinting = gxLuminanceTint;
  2145.         pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
  2146.     }
  2147.  
  2148.  
  2149. /******* Clean-up *******/
  2150.  
  2151. FailedToLoadDraftTable:
  2152. Forward_GXSetupImageData:
  2153.     return(anErr);
  2154. }
  2155. /* SD_SetupImageData */
  2156.  
  2157.  
  2158. /****************************************************************************************
  2159.  
  2160.                             SD_FetchTaggedData
  2161.                             
  2162.     function:
  2163.                 This routine is called by the Printing Manager when a resource is fetched
  2164.                 from some resource file.  This driver overrides this message to determine
  2165.                 when someone is fetching the 'cust' resource.  If this resource
  2166.                 is being fetched, and the job we're processing is not best quality, then
  2167.                 we lower the resolution in the 'cust' resource handle returned to be 72 dpi.
  2168.                 This ensures the translation from QuickDraw to QuickDraw GX is done at the
  2169.                 proper resolution.
  2170.                 
  2171.     parameters:    
  2172.                 rsrcType            type of the resource being retrieved
  2173.                 rsrcID            resource ID of the resource being retrieved
  2174.                 theRsrc            handle to the resource retrieved
  2175.                 owner                indicates who is issuing the request; only look at owners == 'drvr'
  2176.                 
  2177.     returns:
  2178.                 OSErr
  2179.  
  2180. ****************************************************************************************/
  2181. OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
  2182. {
  2183.     OSErr        anErr;
  2184.     
  2185.     if (owner == 'drvr')                                                    //    T => Fetching a driver resource
  2186.     {
  2187.         if (    (rsrcType == gxTrayCountDataType)    &&                    //    T => type is trayCountData
  2188.                 (rsrcID == gxTrayCountDataID)                            //    T => ID is trayCountData
  2189.             )
  2190.         {
  2191.             // Remap as required
  2192.             rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFeederRsrcID : kDefaultTrayRsrcID);
  2193.         }
  2194.         else if (    (rsrcType == gxTrayNameDataType)    &&            //    T => type is trayName
  2195.                         (rsrcID == kDefaultSheetFdrTray1NameID)    //    T => ID is trayData
  2196.             )
  2197.         {
  2198.             // Remap as required
  2199.             rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFdrTray1NameID : kDefaultTrayNameID);
  2200.         }
  2201.     }
  2202.     
  2203.     // First fetch the actual resource
  2204.     anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
  2205.     require(anErr == noErr, FetchTaggedData);
  2206.     
  2207.     if (    (owner == 'drvr')                &&        //    T => Fetching a driver resource
  2208.             (rsrcType == gxCustType)    &&        //    T => type is 'cust'
  2209.             (rsrcID == gxCustID)            &&        //    T => ID is -8192
  2210.             !JobIsBestQuality()                    //    T => Doing rough output
  2211.         )
  2212.     {
  2213.         gxCustomizationHdl    custData;
  2214.         
  2215.         // Change the 'cust' resolution to specify low res translation from QuickDraw to QuickDraw GX
  2216.         (*custData)->horizontalResolution = 72;
  2217.         (*custData)->verticalResolution = 72;
  2218.     }
  2219.  
  2220.  
  2221. /******* Clean-up *******/
  2222.  
  2223. FetchTaggedData:
  2224.     return(anErr);
  2225. }
  2226. /* SD_FetchTaggedData */
  2227.  
  2228.  
  2229. /****************************************************************************************
  2230.  
  2231.                             SD_DefaultDesktopPrinter
  2232.                             
  2233.     function:
  2234.                 This routine is called by the Printing Manager when a new desktop printer is
  2235.                 created.  We take this opportunity to open a connection to the LQ printer to
  2236.                 see how it's configured.  Specifically, we determine if there are trays
  2237.                 attached and if there is a color ribbon installed.  Based upon the device query,
  2238.                 we update the desktop printer file.
  2239.                 
  2240.     parameters:    
  2241.                 printerName        Name of the printer being created
  2242.                 
  2243.     returns:
  2244.                 OSErr
  2245.  
  2246. ****************************************************************************************/
  2247. OSErr SD_DefaultDesktopPrinter(Str31 printerName)
  2248. {
  2249.     OSErr        anErr;
  2250.     
  2251.     // First let the Printing Manager create the desktop printer
  2252.     anErr = Forward_GXDefaultDesktopPrinter(printerName);
  2253.     require(anErr == noErr, DefaultDesktopPrinter);
  2254.     
  2255.     // Optional step (now removed): during creation of the printer we could open a connection
  2256.     // to get the current configuration.  However, this has the disadvantage of making the user
  2257.     // wait until the printer is available.  The user can force a configuration update by printing
  2258.     // any document to the printer (even a blank one)
  2259.     
  2260.     // Now we attempt to open a connection to the device (it will update the config. file)
  2261. //    anErr = Send_GXOpenConnection();
  2262. //    require(anErr == noErr, OpenConnection);
  2263.     
  2264.     // A side effect of opening the connection will be that we will have already updated
  2265.     // the configuration information (in the file) that specifies whether a color ribbon
  2266.     // is installed and the number of sheet feeder trays attached (if any). ## The only additional
  2267.     // thing we'd want to do here is to update the number of trays specified in the desktop
  2268.     // printer file to be the actual number of trays attached to the device.  Currently, the 
  2269.     // system assumes the number of trays attached is equivalent to the number of default
  2270.     // trays specified in our driver resources.  Though we can query the printer for the 
  2271.     // exact number of trays, we cannot update the info. in the config. file that specifies
  2272.     // the exact number of trays.  We need a RemoveTrayInfo routine.
  2273.     
  2274.     // Now we just close down the connection
  2275. //    anErr = Send_GXCloseConnection();
  2276. //    check(anErr == noErr);
  2277.  
  2278.     
  2279. /******* Clean-up *******/
  2280.  
  2281. OpenConnection:
  2282. DefaultDesktopPrinter:
  2283.     return(anErr);
  2284. }
  2285. /* SD_DefaultDesktopPrinter */
  2286.  
  2287.  
  2288. /****************************************************************************************
  2289.  
  2290.                             SD_GetDTPMenuList
  2291.                             
  2292.     function:
  2293.                 NOOP.
  2294.                 
  2295.     parameters:    
  2296.                 hMenu            Handle to the menu that's being built
  2297.                 
  2298.     returns:
  2299.                 OSErr
  2300.  
  2301. ****************************************************************************************/
  2302. OSErr SD_GetDTPMenuList(MenuHandle hMenu)
  2303. {
  2304.     return(Forward_GXGetDTPMenuList(hMenu));
  2305. }
  2306. /* SD_GetDTPMenuList */
  2307.  
  2308.  
  2309. /****************************************************************************************
  2310.  
  2311.                             SD_DTPMenuSelect
  2312.                             
  2313.     function:
  2314.                 This routine is called by the Printing Manager when a menu item in the Finder's
  2315.                 Printer menu is selected.  This routine determines if the menu item selected
  2316.                 is the "Input Tray…" item. If it's, then display the dialog which lets the user
  2317.                 specify the paper in the LQ's sheet feeder if we know there are some trays
  2318.                 attached to the printer.  Otherwise, we just pass the item on to others in the chain.
  2319.                 
  2320.     parameters:    
  2321.                 itemNum        Menu item number that was selected
  2322.                 
  2323.     returns:
  2324.                 OSErr
  2325.  
  2326. ****************************************************************************************/
  2327. OSErr SD_DTPMenuSelect(short itemNum)
  2328. {
  2329.     OSErr        anErr;
  2330.     
  2331.     if ((itemNum == gxInputTraysMenuItem) && (PrinterHasTrays() > 0))    //    T => User wants to configure the input trays
  2332.     {
  2333.         anErr = DoSheetfeederDialog();
  2334.         
  2335.     }
  2336.     else    //    T => We didn't process the item
  2337.     {
  2338.         // Pass the message on to others in the chain
  2339.         anErr = Forward_GXDTPMenuSelect(itemNum);
  2340.     }
  2341.     
  2342.     check(anErr == noErr);
  2343.  
  2344.     return(anErr);
  2345. }
  2346. /* SD_DTPMenuSelect */
  2347.  
  2348.  
  2349. /****************************************************************************************
  2350.  
  2351.                             SD_RasterPackageBitmap
  2352.                             
  2353.     function:
  2354.                 This routine is called by the Printing Manager when it has completed rendering
  2355.                 a single portion of a raster page and the driver should now package the data
  2356.                 and output it to the device.  This routine is called to package one complete band.
  2357.                 
  2358.                 It routine does the following:
  2359.                     
  2360.                 1)    Starts filling the buffer from buffer + bufferPos.  Remember
  2361.                     that this pointer may not be word aligned - so be careful
  2362.                     assigning things into it.
  2363.                     
  2364.                 2)    Puts a "fake" set of set margins commands at
  2365.                     the begining of the data.  Since most of the time we don't
  2366.                     know the margins, we save away the value of the bufferPos,
  2367.                     and backpatch it after we have finished with the bitmap.
  2368.                     
  2369.                 3)    Adds in the rotated data for your printer.  The data to stuff starts
  2370.                     at location pPackage->startRaster * pPackage->bitmapToPackage->rowBytes (startY)
  2371.                     in the pPackage->bitmapToPackage bitmap.  Stuffs the bits from here until
  2372.                     we reach startY + <the band size>, which is the size of our single
  2373.                     band in this resolution mode.  Increment our number by 
  2374.                     <your pass offset> + 1, which is the number of microspaces
  2375.                     we will send between head passes to form this band.   Take care
  2376.                     that we don't step off of the end of the bitmap in this operation,
  2377.                     since we may be called with startY at the end of the offscreen if the first part
  2378.                     of the band is white.
  2379.                     
  2380.                     colorBand contains the color band which we should be stuffing, from
  2381.                     1 to the number of color passes our printer needs (4).
  2382.                     Packs in the correct color band.  The packager will call us once
  2383.                     for each color band, and correctly handle line feeds and backward
  2384.                     line feeds to do the correct thing.  If your printer takes full
  2385.                     RGB or CYMK data, define your number of colors to be
  2386.                     1 and pack the full RGB or CYMK data with the one call.
  2387.                     
  2388.                     If you request kSendAllColors in your raster pack resource, then this
  2389.                     message will always be called for all color passes, even those that
  2390.                     do not have data on them.  For some printers, this is useful.  For the
  2391.                     case of the ImageWriter, this option is not specified, so this message
  2392.                     will only be sent for colors that actually have dirty bits within them.
  2393.                     
  2394.                 4)    Backpatches SetMargins from the saved value in step 2) now that we
  2395.                     know the margins.
  2396.                     
  2397.                 5)    Increments bufferPos by the number of bytes we have
  2398.                     added to the buffer.  Be sure to take into account the Set Margins
  2399.                     command.
  2400.  
  2401.     parameters:        
  2402.                 whatToPackage        info. about the bitmap whose data is to be sent to the printer
  2403.                 buffer                buffer in which to place the packaged data
  2404.                 bufferPos            position within buffer of where to place the packaged data
  2405.                 imageData            handle to the raster image data info.
  2406.                 
  2407.     returns:
  2408.                 OSErr
  2409.  
  2410. ****************************************************************************************/
  2411. OSErr SD_RasterPackageBitmap(    gxRasterPackageBitmapRec    *whatToPackage, 
  2412.                                         Ptr                                 buffer,
  2413.                                         unsigned long                     *bufferPos, 
  2414.                                         gxRasterImageDataHdl            imageData)
  2415. {
  2416.     OSErr                    anErr = noErr;
  2417.     ScanLinePtr            pTheScanLine;            // Pointer to the start of scan line data
  2418.     unsigned short        firstDirty;                // First dirty pixel
  2419.     Boolean                bandIsDirty;            // Is this band dirty?
  2420.     unsigned short        whichCol;                // Index into the scan line data of where to place the next data bytes
  2421.     unsigned short        x;                            
  2422.     unsigned long        tempColumn;                // Placeholder for the column of data we're currently assembling
  2423.                                                         //    for 72 dpi:     only high order byte is used
  2424.                                                         //    for 216 dpi:    highest order three bytes are used
  2425.     Ptr                    basePtr;                    // Pointer to current X byte
  2426.     unsigned char        outputMask;                // Mask of bit to set in rotated image
  2427.     unsigned char        inputMask;                // Mask of bit to look at in X
  2428.     unsigned short        yPointerOffset;        // Increment pointer by this to get to next scanline
  2429.     unsigned short        endY;                        //    Last scan line to examine (top-to-bottom)
  2430.     unsigned short        endX;                        //    Last pixel column to examine (left-to-right)
  2431.     unsigned short        incrY;                    //    Number of scan lines to increment by when advancing to the next scan line
  2432.     short                    bytesPerBand;            //    Number of bytes in a single band (1 for 72 dpi, 3 for 216 dpi)
  2433.             
  2434.  
  2435.     // Determine the number of bytes that are in a single band 
  2436.     if ( (*imageData)->hImageRes == ff(72) )    //    T => Low resolution output
  2437.         bytesPerBand = 1;
  2438.     else
  2439.         bytesPerBand = 3;
  2440.     
  2441.     //    Overlay a scan line structure on the buffer we're filling in 
  2442.     pTheScanLine = (ScanLinePtr) (buffer + *bufferPos);
  2443.     
  2444.     // Set color mode for this scan line, if needed 
  2445.     
  2446.     pTheScanLine->cColorEscape = kEscape;
  2447.     pTheScanLine->cSetColorCommand = kSetColorCommand;
  2448.     
  2449.     if ( (*imageData)->packagingInfo.colorPasses == 4 )    //    T => Doing four pass color output
  2450.     {
  2451.         switch (whatToPackage->colorBand)    //    Determine which color to select
  2452.         {
  2453.             case 1: // yellow
  2454.                 pTheScanLine->cColor    = '1';
  2455.                 break;
  2456.                 
  2457.             case 2: // magenta
  2458.                 pTheScanLine->cColor    = '2';
  2459.                 break;
  2460.  
  2461.             case 3: // cyan
  2462.                 pTheScanLine->cColor    = '3';
  2463.                 break;
  2464.                 
  2465.             case 4: // black
  2466.                 pTheScanLine->cColor    = '0';
  2467.                 break;
  2468.         }
  2469.     }
  2470.     else    //    T => Just doing black and white printing; select the color black
  2471.         pTheScanLine->cColor = '0';
  2472.  
  2473.     // We start out with no dirty bits
  2474.     firstDirty = 0;
  2475.     bandIsDirty = false;
  2476.     
  2477.     // Set our array index to zero
  2478.     whichCol = 0;
  2479.     
  2480.     // Get the byte pointer for the start of this color band
  2481.     basePtr = whatToPackage->bitmapToPackage->image;
  2482.     
  2483.     // Get the byte pointer for the start of the first scan line
  2484.     basePtr += whatToPackage->startRaster * whatToPackage->bitmapToPackage->rowBytes;
  2485.             
  2486.     // Save away loop invariants
  2487.     
  2488.     endY = whatToPackage->startRaster + (*imageData)->packagingInfo.headHeight;    // Ending Y scan line
  2489.     incrY = (*imageData)->packagingInfo.passOffset + 1;                                    // Number of scanlines to increment by
  2490.     endX = whatToPackage->dirtyRect.right;                                                        // Ending X pos
  2491.     yPointerOffset = incrY * whatToPackage->bitmapToPackage->rowBytes;                // amount to add to the input pointer to move to the next scanline
  2492.  
  2493.     // If the ending position is too large for the bitmap we have been given,
  2494.     //truncate it, so that we don't print garbage
  2495.  
  2496.     if (endY > whatToPackage->bitmapToPackage->height)
  2497.          endY = whatToPackage->bitmapToPackage->height;
  2498.     
  2499.     // Start with the first bit in the byte sub-band
  2500.     inputMask = 0x80;
  2501.  
  2502.     // For the entire width of the scan line, move a rolling mask along in the
  2503.     // X direction, rotating up 8 or 24 bits of Y data per column.
  2504.     
  2505.     for (x = 0; x < endX; x++)
  2506.     {        
  2507.         Ptr    thePtr;
  2508.  
  2509.         // The bits in this column are clear to begin with
  2510.         tempColumn = 0;
  2511.         
  2512.         // Which byte(s) to look at in the input buffer
  2513.         thePtr = basePtr;
  2514.         
  2515.         // For the number of bytes in a single band, scan through each single  
  2516.         // byte sub-band, setting each of the 8 bits = the bit in that scan line
  2517.         {
  2518.             short                    bitsPerByte;
  2519.             short                    byteSubBand = bytesPerBand;
  2520.             unsigned char        *currByte = (unsigned char *) &tempColumn;
  2521.             short                    currYPos;
  2522.             
  2523.             currYPos = whatToPackage->startRaster;
  2524.             
  2525.             do
  2526.             {
  2527.                 // Where to place the bit in the output. The LQ takes the bit pattern upside down.
  2528.                 outputMask = 0x01;
  2529.         
  2530.                 bitsPerByte = 8;
  2531.                 while ( (bitsPerByte > 0) && (currYPos < endY) )
  2532.                 {
  2533.                     // If we have a bit turned on in the input, rotate it into the output
  2534.                     if ( ((*thePtr) & inputMask) != 0 )
  2535.                         *currByte |= outputMask;
  2536.         
  2537.                     // move onto next position in the output data                
  2538.                     outputMask <<= 1;
  2539.                     
  2540.                     // move onto the next scan line in the input data
  2541.                     thePtr += yPointerOffset;
  2542.                     
  2543.                     // Indicate we processed one of the bits
  2544.                     bitsPerByte--;
  2545.                     
  2546.                     // Keep track of our Y position as we move down the column
  2547.                     currYPos += incrY;
  2548.                 }
  2549.                 
  2550.                 if (currYPos >= endY)    //    T => We're done with this column
  2551.                     break;
  2552.                     
  2553.                 // Indicate we processed one of the byte rows in the band
  2554.                 byteSubBand--;
  2555.                 
  2556.                 // Bump to the next byte to fill in tempColumn
  2557.                 currByte++;
  2558.             }
  2559.             while (byteSubBand > 0);
  2560.         }
  2561.             
  2562.         // Save the column info (a max. of three bytes). Note: we'll only advance whichCol based upon the number of bytes per band
  2563.         BlockMove((Ptr) &tempColumn, (Ptr) &(pTheScanLine->iTheData[whichCol]), 3);
  2564.         
  2565.         // If we have some form of data, then mark that this band is dirty
  2566.         if (tempColumn != 0)
  2567.         {
  2568.             if (!bandIsDirty)    //    T => Not already dirty; remember the first dirty pixel
  2569.             {
  2570.                 /* These are the first dirty pixels we have seen so far */
  2571.                 bandIsDirty = true;
  2572.                 firstDirty = x;
  2573.             }
  2574.         }
  2575.             
  2576.         // If we have some dirty bits, adjust the whichCol variable based upon the number of bytes in a band
  2577.         if (bandIsDirty)
  2578.         {
  2579.             // Move on to the next column or set of columns
  2580.             whichCol += bytesPerBand;
  2581.         }
  2582.  
  2583.         // Position for the next bit in the input byte currently referenced by basePtr
  2584.         inputMask >>= 1;
  2585.         
  2586.         if (inputMask == 0)    //    T => Need to reset the input mask and advance the pointer
  2587.         {
  2588.             // Get the next byte
  2589.             basePtr++;
  2590.             
  2591.             // Reset the bit mask to the first bit
  2592.             inputMask = 0x80;
  2593.         }
  2594.     } // end of loop for width of bitmap
  2595.  
  2596.     // If we have a dirty band, fill in the left margin setting and add a carriage return to the end
  2597.     if (bandIsDirty)
  2598.     {            
  2599.         // Set the left margin to be the first dirty pixel in the scan line
  2600.         {
  2601.             SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  2602.             
  2603.             check(hGlobals);
  2604.             
  2605.             // Stuff in the set margin command
  2606.             
  2607.             pTheScanLine->cMarginsEscape = kEscape;
  2608.             pTheScanLine->cMarginsCommand = (bytesPerBand == 1) ? kLowResMarginsCommand : kHighResMarginsCommand;
  2609.             
  2610.             // Convert left margin into ASCII and place it at the start of the scan line
  2611.             Long2Dec((*hGlobals)->leftMargin + firstDirty, (Ptr) (pTheScanLine->cIndentDistance));
  2612.         }
  2613.         
  2614.         // Now fill in the last escape sequence command depending upon if we're doing low-res or high-res graphics
  2615.         
  2616.         pTheScanLine->cEscape = kEscape;
  2617.         pTheScanLine->cCommand = (bytesPerBand == 1)    ? kLowResGraphicsCommand : kHighResGraphicsCommand;
  2618.  
  2619.         // If we're doing high-res, then whichCol must be divided by three to compensate for the 3-byte buffer entries
  2620.         {
  2621.             short        adjustedWhichCol = whichCol;
  2622.             
  2623.             if (bytesPerBand == 3)
  2624.                 adjustedWhichCol /= 3;
  2625.                 
  2626.             Long2Dec(adjustedWhichCol, (Ptr) (pTheScanLine->cLineStrLength));
  2627.         }
  2628.         
  2629.         
  2630.         //    Increment the count of the number of bytes that have been added to the buffer
  2631.         *bufferPos += kScanLineHdrSize + whichCol;
  2632.  
  2633.         // Lastly, put a <cr> at the end of the line
  2634.         *(buffer + *bufferPos) = '\n';
  2635.         *bufferPos += 1;
  2636.     }
  2637.         
  2638.     return(anErr);
  2639. }
  2640. /* SD_RasterPackageBitmap */
  2641.  
  2642.  
  2643. /****************************************************************************************
  2644.  
  2645.                             SD_RasterLineFeed
  2646.                             
  2647.     function:
  2648.                 This routine is called by the Printing Manager to send the appropriate line
  2649.                 feed commands to the printer i norder to skip up or down the page the 
  2650.                 equivalent of lineFeedSize pixels.
  2651.                 
  2652.     parameters:    
  2653.                 lineFeedSize    number of pixels to line feed by
  2654.                 buffer            buffer in which to place the linefeed packaging commands
  2655.                 bufferPos        offset within buffer at which to place the linefeed commands
  2656.                 imageData        handle to the raster image data
  2657.                 
  2658.     returns:
  2659.                 OSErr
  2660.  
  2661. ****************************************************************************************/
  2662. OSErr SD_RasterLineFeed(short                     *lineFeedSize, 
  2663.                                 Ptr                         buffer, 
  2664.                                 unsigned long            *bufferPos, 
  2665.                                 gxRasterImageDataHdl    imageData)
  2666. {
  2667.     OSErr        anErr = noErr;
  2668.     
  2669.     // If there is no need for any line feeds, then just return now
  2670.     if (*lineFeedSize == 0)
  2671.         return(anErr);
  2672.         
  2673.     // If we are in low res mode, we double the line feed size, as all ImageWriter LQ 
  2674.     // line feed commands are expressed at 144 dpi.
  2675.     if ( (*imageData)->vImageRes == ff(72) )
  2676.     {
  2677.         *lineFeedSize <<= 1;
  2678.         
  2679.         // do the line feed in the default way
  2680.         anErr = Forward_GXRasterLineFeed(lineFeedSize, buffer, bufferPos, imageData);
  2681.  
  2682.         *lineFeedSize >>= 1;
  2683.     }
  2684.     else    //    T => In high res. mode; must determine the number of 1/144 inch and 1/216 inch line feeds needed
  2685.     {
  2686.         Ptr        nextByte;    
  2687.         fixed        lineFeedInInches;
  2688.         fixed        oneOver144;
  2689.         fixed        remainder;
  2690.         short        num216FractLineFeeds;
  2691.         fixed        num144FractLineFeeds;
  2692.         Str31        aNumber;
  2693.                         
  2694.         // Determine the location at which we'll begin inserting commands
  2695.         nextByte = buffer + *bufferPos;
  2696.         
  2697.         // Is line feed movement going to be backward?
  2698.         if ( *lineFeedSize < 0 )
  2699.         {
  2700.             *lineFeedSize = -(*lineFeedSize);    // Force positive
  2701.             
  2702.             // Add the backward direction command to the buffer
  2703.             *nextByte++ = kEscape;
  2704.             *nextByte++ = 'r';
  2705.         }
  2706.         else    //    T => Paper motion is forward
  2707.         {
  2708.             // Add the forward direction command to the buffer
  2709.             *nextByte++ = kEscape;
  2710.             *nextByte++ = 'f';
  2711.         }
  2712.         
  2713.         // Update the count of the number of bytes added to the buffer
  2714.         *bufferPos += 2;
  2715.         
  2716.         // Determine the number of inches we need to skip with the line feed command
  2717.         lineFeedInInches = FixDiv( IntToFixed(*lineFeedSize), ff(216) );
  2718.         
  2719.         // Determine the integral number of 1/144 inch increments the line feed space comprises
  2720.         
  2721.         oneOver144 = FixDiv(ff(1), ff(144));
  2722.         num144FractLineFeeds = FixDiv( lineFeedInInches, oneOver144 );
  2723.         
  2724.         // Determine the remaining 1/216 inch line feeds we'll need to add to the buffer
  2725.         
  2726.         remainder = lineFeedInInches - FixMul( IntToFixed( FixedToInt(num144FractLineFeeds) ), oneOver144 );
  2727.         num216FractLineFeeds = FixedToInt( FixDiv( remainder, FixDiv( ff(1), ff(216) ) ) );
  2728.         
  2729.         // Send the line feed spacing commands and the line feeds necessary for the 1/144th's portion of the movement
  2730.         {
  2731.             short        numOne144ths = FixedToInt(num144FractLineFeeds);
  2732.             
  2733.             if (numOne144ths >= 99)    //    T => We can do a max. of 99/144 inch movement at a time
  2734.             {
  2735.                 //    Add the line feed spacing command to the buffer
  2736.                 *nextByte++ = kEscape;
  2737.                 *nextByte++ = 'T';
  2738.                 *nextByte++ = '9';
  2739.                 *nextByte++ = '9';
  2740.                 
  2741.                 // Update the count of the number of bytes added to the buffer
  2742.                 *bufferPos += 4;
  2743.         
  2744.                 do
  2745.                 {
  2746.                     *nextByte++ = kLineFeed;        // line feed
  2747.                     
  2748.                     // Update the count of the number of bytes added to the buffer
  2749.                     *bufferPos += 1;
  2750.         
  2751.                     numOne144ths -= 99;
  2752.                 }
  2753.                 while (numOne144ths >= 99);
  2754.             }
  2755.                 
  2756.             // Send remaining line feeds to finish off the 1/144th's portion of the movement
  2757.  
  2758.             if (numOne144ths > 0)    //    T => Still more movement
  2759.             {
  2760.                 *nextByte++ = kEscape;
  2761.                 *nextByte++ = 'T';
  2762.                 
  2763.                 NumToString(numOne144ths, aNumber);
  2764.                 if ( StrLength(aNumber) == 1 )
  2765.                 {
  2766.                     *nextByte++ = '0';
  2767.                     *nextByte++ = aNumber[1];
  2768.                 }
  2769.                 else
  2770.                 {
  2771.                     *nextByte++ = aNumber[1];
  2772.                     *nextByte++ = aNumber[2];
  2773.                 }
  2774.                 
  2775.                 // Add the linefeed character
  2776.                 *nextByte++ = kLineFeed;
  2777.  
  2778.                 // Update the count of the number of bytes added to the buffer
  2779.                 *bufferPos += 5;
  2780.             }
  2781.         }
  2782.         
  2783.         // Now send any spacing command for the remaining 1/216th portion of the movement if needed
  2784.         if (num216FractLineFeeds > 0)
  2785.         {
  2786.             NumToString(num216FractLineFeeds, aNumber);
  2787.             
  2788.             // Add the command to the buffer: <Esc> t <num line feeds>
  2789.             
  2790.             *nextByte++ = kEscape;
  2791.             *nextByte++ = 't';
  2792.             *nextByte = aNumber[1];
  2793.             
  2794.             // Bump the buffer byte count to account for these new characters
  2795.             *bufferPos += 3;
  2796.         }
  2797.  
  2798.         // We always handle the entire linefeed request so we can zero lineFeedSize
  2799.         *lineFeedSize = 0;
  2800.     }
  2801.  
  2802.     return(anErr);
  2803. }
  2804. /* SD_RasterLineFeed */
  2805.  
  2806.  
  2807.